Skip to content

Commit

Permalink
Revert PR #161: Replace schedulers with AgentSet functionality (#170)
Browse files Browse the repository at this point in the history
This commit reverts PR #161 #161

That PR assumed that time advancement would be done automatically, like proposed in projectmesa/mesa#2223

We encountered some underlying issues with time, which we couldn't resolve in time.
  • Loading branch information
EwoutH authored Aug 22, 2024
1 parent 0ebc4d1 commit 43622b9
Show file tree
Hide file tree
Showing 28 changed files with 170 additions and 123 deletions.
16 changes: 7 additions & 9 deletions examples/bank_reserves/bank_reserves/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@
Northwestern University, Evanston, IL.
"""

from .random_walk import RandomWalker
import mesa

from .random_walk import RandomWalker

class Bank:
"""Note that the Bank class is not a Mesa Agent, but just a regular Python
class. This is because there is only one bank in this model, and it does not
use any Mesa-specific features like the scheduler or the grid, and doesn't
have a step method. It is just used to keep track of the bank's reserves and
the amount it can loan out, for Person agents to interact with."""

def __init__(self, model, reserve_percent=50):
self.model = model
class Bank(mesa.Agent):
def __init__(self, unique_id, model, reserve_percent=50):
# initialize the parent class with required parameters
super().__init__(unique_id, model)
# for tracking total value of loans outstanding
self.bank_loans = 0
"""percent of deposits the bank must keep in reserves - this is set via
Expand Down Expand Up @@ -176,6 +173,7 @@ def take_out_loan(self, amount):
# increase the bank's outstanding loans
self.bank.bank_loans += amount

# step is called for each agent in model.BankReservesModel.schedule.step()
def step(self):
# move to a cell in my Moore neighborhood
self.random_move()
Expand Down
22 changes: 13 additions & 9 deletions examples/bank_reserves/bank_reserves/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,40 @@
def get_num_rich_agents(model):
"""return number of rich agents"""

rich_agents = [a for a in model.agents if a.savings > model.rich_threshold]
rich_agents = [a for a in model.schedule.agents if a.savings > model.rich_threshold]
return len(rich_agents)


def get_num_poor_agents(model):
"""return number of poor agents"""

poor_agents = [a for a in model.agents if a.loans > 10]
poor_agents = [a for a in model.schedule.agents if a.loans > 10]
return len(poor_agents)


def get_num_mid_agents(model):
"""return number of middle class agents"""

mid_agents = [
a for a in model.agents if a.loans < 10 and a.savings < model.rich_threshold
a
for a in model.schedule.agents
if a.loans < 10 and a.savings < model.rich_threshold
]
return len(mid_agents)


def get_total_savings(model):
"""sum of all agents' savings"""

agent_savings = [a.savings for a in model.agents]
agent_savings = [a.savings for a in model.schedule.agents]
# return the sum of agents' savings
return np.sum(agent_savings)


def get_total_wallets(model):
"""sum of amounts of all agents' wallets"""

agent_wallets = [a.wallet for a in model.agents]
agent_wallets = [a.wallet for a in model.schedule.agents]
# return the sum of all agents' wallets
return np.sum(agent_wallets)

Expand All @@ -73,7 +75,7 @@ def get_total_money(model):

def get_total_loans(model):
# list of amounts of all agents' loans
agent_loans = [a.loans for a in model.agents]
agent_loans = [a.loans for a in model.schedule.agents]
# return sum of all agents' loans
return np.sum(agent_loans)

Expand Down Expand Up @@ -116,7 +118,7 @@ def __init__(
self.height = height
self.width = width
self.init_people = init_people

self.schedule = mesa.time.RandomActivation(self)
self.grid = mesa.space.MultiGrid(self.width, self.height, torus=True)
# rich_threshold is the amount of savings a person needs to be considered "rich"
self.rich_threshold = rich_threshold
Expand All @@ -136,7 +138,7 @@ def __init__(
)

# create a single bank for the model
self.bank = Bank(self, self.reserve_percent)
self.bank = Bank(1, self, self.reserve_percent)

# create people for the model according to number of people set by user
for i in range(self.init_people):
Expand All @@ -146,13 +148,15 @@ def __init__(
p = Person(i, self, True, self.bank, self.rich_threshold)
# place the Person object on the grid at coordinates (x, y)
self.grid.place_agent(p, (x, y))
# add the Person object to the model schedule
self.schedule.add(p)

self.running = True
self.datacollector.collect(self)

def step(self):
# tell all the agents in the model to run their step function
self.agents.shuffle().do("step")
self.schedule.step()
# collect data
self.datacollector.collect(self)

Expand Down
24 changes: 14 additions & 10 deletions examples/bank_reserves/batch_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@
def get_num_rich_agents(model):
"""list of rich agents"""

rich_agents = [a for a in model.agents if a.savings > model.rich_threshold]
rich_agents = [a for a in model.schedule.agents if a.savings > model.rich_threshold]
# return number of rich agents
return len(rich_agents)


def get_num_poor_agents(model):
"""list of poor agents"""

poor_agents = [a for a in model.agents if a.loans > 10]
poor_agents = [a for a in model.schedule.agents if a.loans > 10]
# return number of poor agents
return len(poor_agents)

Expand All @@ -54,7 +54,9 @@ def get_num_mid_agents(model):
"""list of middle class agents"""

mid_agents = [
a for a in model.agents if a.loans < 10 and a.savings < model.rich_threshold
a
for a in model.schedule.agents
if a.loans < 10 and a.savings < model.rich_threshold
]
# return number of middle class agents
return len(mid_agents)
Expand All @@ -63,15 +65,15 @@ def get_num_mid_agents(model):
def get_total_savings(model):
"""list of amounts of all agents' savings"""

agent_savings = [a.savings for a in model.agents]
agent_savings = [a.savings for a in model.schedule.agents]
# return the sum of agents' savings
return np.sum(agent_savings)


def get_total_wallets(model):
"""list of amounts of all agents' wallets"""

agent_wallets = [a.wallet for a in model.agents]
agent_wallets = [a.wallet for a in model.schedule.agents]
# return the sum of all agents' wallets
return np.sum(agent_wallets)

Expand All @@ -89,7 +91,7 @@ def get_total_money(model):
def get_total_loans(model):
"""list of amounts of all agents' loans"""

agent_loans = [a.loans for a in model.agents]
agent_loans = [a.loans for a in model.schedule.agents]
# return sum of all agents' loans
return np.sum(agent_loans)

Expand Down Expand Up @@ -127,7 +129,7 @@ def __init__(
self.height = height
self.width = width
self.init_people = init_people

self.schedule = mesa.time.RandomActivation(self)
self.grid = mesa.space.MultiGrid(self.width, self.height, torus=True)
# rich_threshold is the amount of savings a person needs to be considered "rich"
self.rich_threshold = rich_threshold
Expand All @@ -148,8 +150,8 @@ def __init__(
agent_reporters={"Wealth": "wealth"},
)

# create a single bank object for the model
self.bank = Bank(self, self.reserve_percent)
# create a single bank for the model
self.bank = Bank(1, self, self.reserve_percent)

# create people for the model according to number of people set by user
for i in range(self.init_people):
Expand All @@ -160,14 +162,16 @@ def __init__(
p = Person(i, (x, y), self, True, self.bank, self.rich_threshold)
# place the Person object on the grid at coordinates (x, y)
self.grid.place_agent(p, (x, y))
# add the Person object to the model schedule
self.schedule.add(p)

self.running = True

def step(self):
# collect data
self.datacollector.collect(self)
# tell all the agents in the model to run their step function
self.agents.shuffle().do("step")
self.schedule.step()

def run_model(self):
for i in range(self.run_time):
Expand Down
2 changes: 1 addition & 1 deletion examples/boid_flockers/Flocker Test.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"def draw_boids(model):\n",
" x_vals = []\n",
" y_vals = []\n",
" for boid in model.agents:\n",
" for boid in model.schedule.agents:\n",
" x, y = boid.pos\n",
" x_vals.append(x)\n",
" y_vals.append(y)\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(self, portrayal_method=None, canvas_height=500, canvas_width=500):

def render(self, model):
space_state = []
for obj in model.agents:
for obj in model.schedule.agents:
portrayal = self.portrayal_method(obj)
x, y = obj.pos
x = (x - model.space.x_min) / (model.space.x_max - model.space.x_min)
Expand Down
5 changes: 3 additions & 2 deletions examples/boid_flockers/boid_flockers/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def __init__(
self.vision = vision
self.speed = speed
self.separation = separation

self.schedule = mesa.time.RandomActivation(self)
self.space = mesa.space.ContinuousSpace(width, height, True)
self.factors = {"cohere": cohere, "separate": separate, "match": match}
self.make_agents()
Expand All @@ -144,6 +144,7 @@ def make_agents(self):
**self.factors,
)
self.space.place_agent(boid, pos)
self.schedule.add(boid)

def step(self):
self.agents.shuffle().do("step")
self.schedule.step()
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


def compute_gini(model):
agent_wealths = [agent.wealth for agent in model.agents]
agent_wealths = [agent.wealth for agent in model.schedule.agents]
x = sorted(agent_wealths)
N = model.num_agents
B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x))
Expand All @@ -21,14 +21,14 @@ def __init__(self, N=100, width=10, height=10):
super().__init__()
self.num_agents = N
self.grid = mesa.space.MultiGrid(width, height, True)

self.schedule = mesa.time.RandomActivation(self)
self.datacollector = mesa.DataCollector(
model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}
)
# Create agents
for i in range(self.num_agents):
a = MoneyAgent(i, self)

self.schedule.add(a)
# Add the agent to a random grid cell
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
Expand All @@ -38,7 +38,7 @@ def __init__(self, N=100, width=10, height=10):
self.datacollector.collect(self)

def step(self):
self.agents.shuffle().do("step")
self.schedule.step()
# collect data
self.datacollector.collect(self)

Expand Down
8 changes: 4 additions & 4 deletions examples/boltzmann_wealth_model_experimental/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


def compute_gini(model):
agent_wealths = [agent.wealth for agent in model.agents]
agent_wealths = [agent.wealth for agent in model.schedule.agents]
x = sorted(agent_wealths)
N = model.num_agents
B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x))
Expand All @@ -21,14 +21,14 @@ def __init__(self, N=100, width=10, height=10):
super().__init__()
self.num_agents = N
self.grid = mesa.space.MultiGrid(width, height, True)

self.schedule = mesa.time.RandomActivation(self)
self.datacollector = mesa.DataCollector(
model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}
)
# Create agents
for i in range(self.num_agents):
a = MoneyAgent(i, self)

self.schedule.add(a)
# Add the agent to a random grid cell
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
Expand All @@ -38,7 +38,7 @@ def __init__(self, N=100, width=10, height=10):
self.datacollector.collect(self)

def step(self):
self.agents.shuffle().do("step")
self.schedule.step()
# collect data
self.datacollector.collect(self)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


def compute_gini(model):
agent_wealths = [agent.wealth for agent in model.agents]
agent_wealths = [agent.wealth for agent in model.schedule.agents]
x = sorted(agent_wealths)
N = model.num_agents
B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x))
Expand All @@ -19,7 +19,7 @@ def __init__(self, num_agents=7, num_nodes=10):
self.num_nodes = num_nodes if num_nodes >= self.num_agents else self.num_agents
self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0.5)
self.grid = mesa.space.NetworkGrid(self.G)

self.schedule = mesa.time.RandomActivation(self)
self.datacollector = mesa.DataCollector(
model_reporters={"Gini": compute_gini},
agent_reporters={"Wealth": lambda _: _.wealth},
Expand All @@ -30,15 +30,15 @@ def __init__(self, num_agents=7, num_nodes=10):
# Create agents
for i in range(self.num_agents):
a = MoneyAgent(i, self)

self.schedule.add(a)
# Add the agent to a random node
self.grid.place_agent(a, list_of_random_nodes[i])

self.running = True
self.datacollector.collect(self)

def step(self):
self.agents.shuffle().do("step")
self.schedule.step()
# collect data
self.datacollector.collect(self)

Expand Down
6 changes: 4 additions & 2 deletions examples/caching_and_replay/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(
self.homophily = homophily
self.radius = radius

self.schedule = mesa.time.RandomActivation(self)
self.grid = mesa.space.SingleGrid(width, height, torus=True)

self.happy = 0
Expand All @@ -86,6 +87,7 @@ def __init__(
agent_type = 1 if self.random.random() < self.minority_pc else 0
agent = SchellingAgent(self.next_id(), self, agent_type)
self.grid.place_agent(agent, pos)
self.schedule.add(agent)

self.datacollector.collect(self)

Expand All @@ -94,9 +96,9 @@ def step(self):
Run one step of the model.
"""
self.happy = 0 # Reset counter of happy agents
self.agents.shuffle().do("step")
self.schedule.step()

self.datacollector.collect(self)

if self.happy == len(self.agents):
if self.happy == self.schedule.get_agent_count():
self.running = False
Loading

0 comments on commit 43622b9

Please sign in to comment.