Skip to content

Commit

Permalink
Minor edits to benchmarking code (#1985)
Browse files Browse the repository at this point in the history
* Make RandomActivationByType.agents_by_type backward compatible

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* updated warning

* Update .gitignore

* Update global_benchmark.py

* pep8 rename

* Update schelling.py

* Update schelling.py

* Update schelling.py

* Update schelling.py

* Squashed commit of the following:

commit c0de4a1
Author: Ewout ter Hoeven <E.M.terHoeven@student.tudelft.nl>
Date:   Sun Jan 21 14:43:08 2024 +0100

    Add CI workflow for performance benchmarks (#1983)

    This commit introduces a new GitHub Actions workflow for performance benchmarking. The workflow is triggered on `pull_request_target` events and can be triggered with a "/rerun-benchmarks" comment in the PR. It should be compatible with PRs from both forks and the main repository. It includes steps for setting up the environment, checking out the PR and main branches, installing dependencies, and running benchmarks on both branches. The results are then compared, encoded, and posted as a comment on the PR.

* Revert "Squashed commit of the following:"

This reverts commit 9485087.

* Update .gitignore

* further updates

* Update benchmarks/WolfSheep/__init__.py

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
quaquel and pre-commit-ci[bot] authored Jan 21, 2024
1 parent 72b0a9d commit 4d0eeec
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 97 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Benchmarking
benchmarking/**/*.pickle
benchmarks/**/*.pickle

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down Expand Up @@ -69,6 +69,7 @@ target/

# PyCharm environment files
.idea/
*.pclprof

# VSCode environment files
.vscode/
Expand All @@ -88,3 +89,4 @@ pythonenv*/
# JS dependencies
mesa/visualization/templates/external/
mesa/visualization/templates/js/external/

80 changes: 0 additions & 80 deletions benchmarks/Flocking/Flocking.py

This file was deleted.

90 changes: 89 additions & 1 deletion benchmarks/Flocking/boid.py → benchmarks/Flocking/flocking.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
"""
Flockers
=============================================================
A Mesa implementation of Craig Reynolds's Boids flocker model.
Uses numpy arrays to represent vectors.
"""

import numpy as np

from mesa import Agent
from mesa import Agent, Model
from mesa.space import ContinuousSpace
from mesa.time import RandomActivation


class Boid(Agent):
Expand Down Expand Up @@ -79,3 +88,82 @@ def step(self):
self.velocity /= np.linalg.norm(self.velocity)
new_pos = self.pos + self.velocity * self.speed
self.model.space.move_agent(self, new_pos)


class BoidFlockers(Model):
"""
Flocker model class. Handles agent creation, placement and scheduling.
"""

def __init__(
self,
seed,
population,
width,
height,
vision,
speed=1,
separation=1,
cohere=0.03,
separate=0.015,
match=0.05,
):
"""
Create a new Flockers model.
Args:
population: Number of Boids
width, height: Size of the space.
speed: How fast should the Boids move.
vision: How far around should each Boid look for its neighbors
separation: What's the minimum distance each Boid will attempt to
keep from any other
cohere, separate, match: factors for the relative importance of
the three drives."""
super().__init__(seed=seed)
self.population = population
self.vision = vision
self.speed = speed
self.separation = separation
self.schedule = RandomActivation(self)
self.space = ContinuousSpace(width, height, True)
self.factors = {"cohere": cohere, "separate": separate, "match": match}
self.make_agents()

def make_agents(self):
"""
Create self.population agents, with random positions and starting headings.
"""
for i in range(self.population):
x = self.random.random() * self.space.x_max
y = self.random.random() * self.space.y_max
pos = np.array((x, y))
velocity = np.random.random(2) * 2 - 1
boid = Boid(
i,
self,
pos,
self.speed,
velocity,
self.vision,
self.separation,
**self.factors,
)
self.space.place_agent(boid, pos)
self.schedule.add(boid)

def step(self):
self.schedule.step()


if __name__ == "__main__":
import time

# model = BoidFlockers(15, 200, 100, 100, 5)
model = BoidFlockers(15, 400, 100, 100, 15)

start_time = time.perf_counter()
for _ in range(100):
model.step()

print(time.perf_counter() - start_time)
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import random

from mesa import Agent, Model
from mesa.space import SingleGrid
Expand All @@ -10,22 +9,20 @@ class SchellingAgent(Agent):
Schelling segregation agent
"""

def __init__(self, pos, model, agent_type):
def __init__(self, unique_id, model, agent_type):
"""
Create a new Schelling agent.
Args:
unique_id: Unique identifier for the agent.
x, y: Agent initial location.
agent_type: Indicator for the agent's type (minority=1, majority=0)
"""
super().__init__(pos, model)
self.pos = pos
super().__init__(unique_id, model)
self.type = agent_type

def step(self):
similar = 0
r = self.model.radius
for neighbor in self.model.grid.iter_neighbors(self.pos, moore=True, radius=r):
for neighbor in self.model.grid.iter_neighbors(self.pos, moore=True, radius=self.model.radius):
if neighbor.type == self.type:
similar += 1

Expand All @@ -36,7 +33,7 @@ def step(self):
self.model.happy += 1


class SchellingModel(Model):
class Schelling(Model):
"""
Model class for the Schelling segregation model.
"""
Expand All @@ -63,9 +60,9 @@ def __init__(
# the coordinates of a cell as well as
# its contents. (coord_iter)
for _cont, pos in self.grid.coord_iter():
if random.random() < self.density: # noqa: S311
agent_type = 1 if random.random() < self.minority_pc else 0 # noqa: S311
agent = SchellingAgent(pos, self, agent_type)
if self.random.random() < self.density:
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)

Expand All @@ -75,3 +72,16 @@ def step(self):
"""
self.happy = 0 # Reset counter of happy agents
self.schedule.step()


if __name__ == "__main__":
import time

# model = Schelling(15, 40, 40, 3, 1, 0.625)
model = Schelling(15, 100, 100, 8, 2, 0.8)

start_time = time.perf_counter()
for _ in range(100):
model.step()

print(time.perf_counter() - start_time)
14 changes: 14 additions & 0 deletions benchmarks/WolfSheep/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .wolf_sheep import WolfSheep

if __name__ == "__main__":
# for profiling this benchmark model
import time

# model = WolfSheep(15, 25, 25, 60, 40, 0.2, 0.1, 20)
model = WolfSheep(15, 100, 100, 1000, 500, 0.4, 0.2, 20)

start_time = time.perf_counter()
for _ in range(100):
model.step()

print(time.perf_counter() - start_time)
File renamed without changes.
8 changes: 4 additions & 4 deletions benchmarks/configurations.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from Flocking.Flocking import BoidFlockers
from Schelling.Schelling import SchellingModel
from WolfSheep.WolfSheep import WolfSheep
from Flocking.flocking import BoidFlockers
from Schelling.schelling import Schelling
from WolfSheep.wolf_sheep import WolfSheep

configurations = {
# Schelling Model Configurations
SchellingModel: {
Schelling: {
"small": {
"seeds": 50,
"replications": 5,
Expand Down
6 changes: 5 additions & 1 deletion benchmarks/global_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import time
import timeit

# making sure we use this version of mesa and not one
# also installed in site_packages or so.
sys.path.insert(0, os.path.abspath(".."))

from configurations import configurations


Expand Down Expand Up @@ -56,7 +60,7 @@ def run_experiments(model_class, config):
mean_run = sum(results[1]) / len(results[1])

print(
f"{time.strftime("%H:%M:%S", time.localtime())} {model.__name__:<14} ({size}) timings: Init {mean_init:.5f} s; Run {mean_run:.4f} s"
f"{time.strftime('%H:%M:%S', time.localtime())} {model.__name__:<14} ({size}) timings: Init {mean_init:.5f} s; Run {mean_run:.4f} s"
)

results_dict[model, size] = results
Expand Down

0 comments on commit 4d0eeec

Please sign in to comment.