Skip to content
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

More pythonic implementation of wolf sheep #2011

Merged
merged 2 commits into from
Jan 29, 2024
Merged
Changes from 1 commit
Commits
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
51 changes: 32 additions & 19 deletions benchmarks/WolfSheep/wolf_sheep.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
Center for Connected Learning and Computer-Based Modeling,
Northwestern University, Evanston, IL.
"""
import math

from mesa import Model, Agent
from mesa import Agent, Model
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 lines can be condensed to be just import mesa, then calling them would be mesa.Agent, mesa.Model, mesa.space.MultiGrid, in line with np.array or pd.DataFrame. See https://github.com/projectmesa/mesa-examples/blob/479eaf389e1a98bda0bdba5aa8f24ede0d84e764/examples/wolf_sheep/wolf_sheep/model.py#L18.

Copy link
Member Author

@quaquel quaquel Jan 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that is slower.

To be clear, I don't care much either way, so if there is some mesa convention for this, I am fine changing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's about the same:

In [1]: import mesa

In [2]: m = mesa.Model()

In [3]: %timeit mesa.Agent(0, m)
627 ns ± 125 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

In [4]: from mesa import Agent, Model

In [5]: m2 = Model()

In [6]: %timeit Agent(0, m2)
627 ns ± 148 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except for the import lines, this PR LGTM.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't have strong opinions on this so if others want to change this as well, fine.

Note, however, that the Schelling model already uses the same style of importing as I have used here. I also personally prefer e.g., SchellingAgent(Agent) over SchellingAgent(mesa.Agent). This is really just a matter of taste.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in the examples repo all uses mesa.x. The ones in the Agents.jl benchmark code are from the outdated version of the examples.

This is really just a matter of taste.

But in the case of Agents.jl benchmark, they count and compare the LOC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in the examples repo all uses mesa.x.

I ment our benchmarks

But in the case of Agents.jl benchmark, they count and compare the LOC.

And we agree that this is only a rough proxy we should not obsess about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ment our benchmarks

The 3 versions of the code (mesa-examples, core Mesa benchmark, Agents.jl) ideally need to be kept in sync.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Once this is merged, I'll happily make PRs on the other libraries.

from mesa.space import MultiGrid
from mesa.time import RandomActivationByType


class Animal(Agent):

def __init__(self, unique_id, model, moore, energy, p_reproduce, energy_from_food):
super().__init__(unique_id, model)
self.energy = energy
Expand All @@ -33,7 +31,12 @@ def random_move(self):
def spawn_offspring(self):
self.energy /= 2
offspring = self.__class__(
self.model.next_id(), self.model, self.moore, self.energy, self.p_reproduce, self.energy_from_food
self.model.next_id(),
self.model,
self.moore,
self.energy,
self.p_reproduce,
self.energy_from_food,
)
self.model.grid.place_agent(offspring, self.pos)
self.model.schedule.add(offspring)
Expand Down Expand Up @@ -72,6 +75,7 @@ def feed(self):
self.energy += self.energy_from_food
grass_patch.fully_grown = False


class Wolf(Animal):
"""
A wolf that walks around, reproduces (asexually) and eats sheep.
Expand Down Expand Up @@ -123,18 +127,18 @@ class WolfSheep(Model):
"""

def __init__(
self,
seed,
height,
width,
initial_sheep,
initial_wolves,
sheep_reproduce,
wolf_reproduce,
grass_regrowth_time,
wolf_gain_from_food=13,
sheep_gain_from_food=5,
moore=False
self,
seed,
height,
width,
initial_sheep,
initial_wolves,
sheep_reproduce,
wolf_reproduce,
grass_regrowth_time,
wolf_gain_from_food=13,
sheep_gain_from_food=5,
moore=False,
):
"""
Create a new Wolf-Sheep model with the given parameters.
Expand Down Expand Up @@ -168,7 +172,14 @@ def __init__(
self.random.randrange(self.height),
)
energy = self.random.randrange(2 * sheep_gain_from_food)
sheep = Sheep(self.next_id(), self, moore, energy, sheep_reproduce, sheep_gain_from_food)
sheep = Sheep(
self.next_id(),
self,
moore,
energy,
sheep_reproduce,
sheep_gain_from_food,
)
self.grid.place_agent(sheep, pos)
self.schedule.add(sheep)

Expand All @@ -179,7 +190,9 @@ def __init__(
self.random.randrange(self.height),
)
energy = self.random.randrange(2 * wolf_gain_from_food)
wolf = Wolf(self.next_id(), self, moore, energy, wolf_reproduce, wolf_gain_from_food)
wolf = Wolf(
self.next_id(), self, moore, energy, wolf_reproduce, wolf_gain_from_food
)
self.grid.place_agent(wolf, pos)
self.schedule.add(wolf)

Expand Down Expand Up @@ -207,4 +220,4 @@ def step(self):
start_time = time.perf_counter()
for _ in range(100):
model.step()
print("Time:", time.perf_counter() - start_time)
print("Time:", time.perf_counter() - start_time)
Loading