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

support for discrete event scheduling #2066

Merged
merged 50 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
92831dd
first commit
quaquel Feb 11, 2024
b7761a8
Update wolf_sheep.py
quaquel Feb 11, 2024
585766b
time unit check and step scheduling in ABMSimulator
quaquel Feb 13, 2024
2d9bce8
ongoing work
quaquel Feb 15, 2024
08de4ff
various small tweaks
quaquel Feb 16, 2024
f2155e5
Epstein Civil Violence as hybrid ABM DES
quaquel Feb 17, 2024
b7457c5
Update epstein_civil_violence.py
quaquel Feb 17, 2024
b0226cf
Merge remote-tracking branch 'upstream/main' into devs
quaquel Feb 24, 2024
cf9efc1
docstrings
quaquel Feb 24, 2024
790c1e6
correct handling of canceling events
quaquel Feb 24, 2024
2fd8069
Merge remote-tracking branch 'upstream/main' into devs
quaquel Feb 28, 2024
9aabc48
docstrings, update to benchmark minor cleaning of public api
quaquel Feb 29, 2024
76ebfed
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 29, 2024
efd79df
make benchmarks work
quaquel Mar 3, 2024
1513095
Merge remote-tracking branch 'upstream/main' into devs
quaquel Mar 3, 2024
d555858
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 3, 2024
6e43ab5
fix for benchmarks
quaquel Mar 3, 2024
ec30623
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 3, 2024
b267bb0
me being stupid
quaquel Mar 3, 2024
53e7ae5
schedule events correctly
Corvince Mar 4, 2024
155517b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 4, 2024
79a30a4
simplified eventlist
Corvince Mar 4, 2024
6c843c9
readded imports
Corvince Mar 4, 2024
5ba27d8
remove need for model.setup
quaquel Mar 11, 2024
f298879
adds a bit more docstring info on eventlist implementation motivation
quaquel Mar 11, 2024
bae814e
cleanup of fully_grown
quaquel Mar 11, 2024
911c919
removal of setup from epstein example
quaquel Mar 11, 2024
4e54add
set time to starttime upon reset
quaquel Mar 11, 2024
1c86aca
move to zero based indexing for _ids
quaquel Mar 11, 2024
2341b79
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 11, 2024
d0611e3
move methods to after init
quaquel Mar 11, 2024
287f138
cleanup
quaquel Mar 11, 2024
6b03f38
unittests for eventlist.py
quaquel Mar 24, 2024
75479d3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 24, 2024
36e9c94
typo fixes
quaquel Mar 24, 2024
1596a6a
simulator unit tests
quaquel Mar 24, 2024
f80fd5b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 24, 2024
a714134
added run_until
quaquel Mar 24, 2024
ca58a70
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 24, 2024
4fc4957
doc string update and benchmark fix
quaquel Mar 24, 2024
25eb453
Merge remote-tracking branch 'upstream/main' into devs
quaquel Mar 24, 2024
0261bc2
Merge branch 'main' into devs
tpike3 Mar 27, 2024
273245d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 27, 2024
046c4be
typo fix
quaquel Apr 7, 2024
586a3a9
Merge remote-tracking branch 'upstream/main' into devs
quaquel Apr 7, 2024
fbd68bc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 7, 2024
8e48a29
deprecate time.DiscreteEventScheduler
quaquel Apr 7, 2024
b7237b8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 7, 2024
47e3c3f
remove unit test for time.DiscreteEventScheduler
quaquel Apr 7, 2024
4f1b88f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 7, 2024
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
28 changes: 15 additions & 13 deletions benchmarks/Flocking/flocking.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def __init__(
cohere=0.03,
separate=0.015,
match=0.05,
simulator=None,
):
"""
Create a new Flockers model.
Expand All @@ -118,18 +119,18 @@ def __init__(
"""
super().__init__(seed=seed)
self.population = population
self.vision = vision
self.speed = speed
self.separation = separation
self.width = width
self.height = height
self.simulator = simulator

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()
self.space = mesa.space.ContinuousSpace(self.width, self.height, True)
self.factors = {
"cohere": cohere,
"separate": separate,
"match": match,
}

def make_agents(self):
"""
Create self.population agents, with random positions and starting directions.
"""
for i in range(self.population):
x = self.random.random() * self.space.x_max
y = self.random.random() * self.space.y_max
Expand All @@ -138,10 +139,11 @@ def make_agents(self):
boid = Boid(
unique_id=i,
model=self,
speed=self.speed,
pos=pos,
speed=speed,
direction=direction,
vision=self.vision,
separation=self.separation,
vision=vision,
separation=separation,
**self.factors,
)
self.space.place_agent(boid, pos)
Expand Down
9 changes: 3 additions & 6 deletions benchmarks/Schelling/schelling.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(
density=0.8,
minority_pc=0.5,
seed=None,
simulator=None,
):
"""
Create a new Schelling model.
Expand All @@ -62,10 +63,8 @@ def __init__(
seed: Seed for Reproducibility
"""
super().__init__(seed=seed)
self.height = height
self.width = width
self.density = density
self.minority_pc = minority_pc
self.simulator = simulator

self.schedule = RandomActivation(self)
self.grid = OrthogonalMooreGrid(
Expand All @@ -75,14 +74,12 @@ def __init__(
random=self.random,
)

self.happy = 0

# Set up agents
# We use a grid iterator that returns
# the coordinates of a cell as well as
# its contents. (coord_iter)
for cell in self.grid:
if self.random.random() < self.density:
if self.random.random() < density:
agent_type = 1 if self.random.random() < self.minority_pc else 0
agent = SchellingAgent(
self.next_id(), self, agent_type, radius, homophily
Expand Down
92 changes: 63 additions & 29 deletions benchmarks/WolfSheep/wolf_sheep.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from mesa import Model
from mesa.experimental.cell_space import CellAgent, OrthogonalVonNeumannGrid
from mesa.time import RandomActivationByType
from mesa.experimental.devs import ABMSimulator


class Animal(CellAgent):
Expand All @@ -36,7 +36,6 @@ def spawn_offspring(self):
self.energy_from_food,
)
offspring.move_to(self.cell)
self.model.schedule.add(offspring)

def feed(self): ...

Expand Down Expand Up @@ -93,26 +92,41 @@ class GrassPatch(CellAgent):
A patch of grass that grows at a fixed rate and it is eaten by sheep
"""

def __init__(self, unique_id, model, fully_grown, countdown):
@property
def fully_grown(self):
return self._fully_grown

@fully_grown.setter
def fully_grown(self, value: bool) -> None:
self._fully_grown = value

if not value:
self.model.simulator.schedule_event_relative(
setattr,
self.grass_regrowth_time,
function_args=[self, "fully_grown", True],
)

def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time):
"""
TODO:: fully grown can just be an int --> so one less param (i.e. countdown)

Creates a new patch of grass

Args:
fully_grown: (boolean) Whether the patch of grass is fully grown or not
countdown: Time for the patch of grass to be fully grown again
grass_regrowth_time : time to fully regrow grass
countdown : Time for the patch of grass to be fully regrown if fully grown is False
"""
super().__init__(unique_id, model)
self.fully_grown = fully_grown
self.countdown = countdown
self._fully_grown = fully_grown
self.grass_regrowth_time = grass_regrowth_time

def step(self):
if not self.fully_grown:
if self.countdown <= 0:
# Set as fully grown
self.fully_grown = True
self.countdown = self.model.grass_regrowth_time
else:
self.countdown -= 1
self.model.simulator.schedule_event_relative(
setattr, countdown, function_args=[self, "fully_grown", True]
)


class WolfSheep(Model):
Expand All @@ -124,6 +138,7 @@ class WolfSheep(Model):

def __init__(
self,
simulator,
height,
width,
initial_sheep,
Expand All @@ -139,27 +154,26 @@ def __init__(
Create a new Wolf-Sheep model with the given parameters.

Args:
simulator: ABMSimulator instance
initial_sheep: Number of sheep to start with
initial_wolves: Number of wolves to start with
sheep_reproduce: Probability of each sheep reproducing each step
wolf_reproduce: Probability of each wolf reproducing each step
wolf_gain_from_food: Energy a wolf gains from eating a sheep
grass: Whether to have the sheep eat grass for energy
grass_regrowth_time: How long it takes for a grass patch to regrow
once it is eaten
sheep_gain_from_food: Energy sheep gain from grass, if enabled.
moore:
seed
seed : the random seed
"""
super().__init__(seed=seed)
# Set parameters
self.height = height
self.width = width
self.simulator = simulator

self.initial_sheep = initial_sheep
self.initial_wolves = initial_wolves
self.grass_regrowth_time = grass_regrowth_time

self.schedule = RandomActivationByType(self)
self.grid = OrthogonalVonNeumannGrid(
[self.height, self.width],
torus=False,
Expand All @@ -175,10 +189,13 @@ def __init__(
)
energy = self.random.randrange(2 * sheep_gain_from_food)
sheep = Sheep(
self.next_id(), self, energy, sheep_reproduce, sheep_gain_from_food
self.next_id(),
self,
energy,
sheep_reproduce,
sheep_gain_from_food,
)
sheep.move_to(self.grid[pos])
self.schedule.add(sheep)

# Create wolves
for _ in range(self.initial_wolves):
Expand All @@ -188,33 +205,50 @@ def __init__(
)
energy = self.random.randrange(2 * wolf_gain_from_food)
wolf = Wolf(
self.next_id(), self, energy, wolf_reproduce, wolf_gain_from_food
self.next_id(),
self,
energy,
wolf_reproduce,
wolf_gain_from_food,
)
wolf.move_to(self.grid[pos])
self.schedule.add(wolf)

# Create grass patches
possibly_fully_grown = [True, False]
for cell in self.grid:
fully_grown = self.random.choice(possibly_fully_grown)
if fully_grown:
countdown = self.grass_regrowth_time
countdown = grass_regrowth_time
else:
countdown = self.random.randrange(self.grass_regrowth_time)
patch = GrassPatch(self.next_id(), self, fully_grown, countdown)
countdown = self.random.randrange(grass_regrowth_time)
patch = GrassPatch(
self.next_id(), self, fully_grown, countdown, grass_regrowth_time
)
patch.move_to(cell)
self.schedule.add(patch)

def step(self):
self.schedule.step()
self.get_agents_of_type(Sheep).shuffle(inplace=True).do("step")
self.get_agents_of_type(Wolf).shuffle(inplace=True).do("step")


if __name__ == "__main__":
import time

model = WolfSheep(25, 25, 60, 40, 0.2, 0.1, 20, seed=15)
simulator = ABMSimulator()
model = WolfSheep(
simulator,
25,
25,
60,
40,
0.2,
0.1,
20,
seed=15,
)

simulator.setup(model)

start_time = time.perf_counter()
for _ in range(100):
model.step()
simulator.run(100)
print("Time:", time.perf_counter() - start_time)
13 changes: 9 additions & 4 deletions benchmarks/global_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from configurations import configurations

from mesa.experimental.devs.simulator import ABMSimulator

# 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(".."))
Expand All @@ -15,13 +17,16 @@
# Generic function to initialize and run a model
def run_model(model_class, seed, parameters):
start_init = timeit.default_timer()
model = model_class(seed=seed, **parameters)
# time.sleep(0.001)
simulator = ABMSimulator()
model = model_class(simulator=simulator, seed=seed, **parameters)
simulator.setup(model)

end_init_start_run = timeit.default_timer()

for _ in range(config["steps"]):
model.step()
simulator.run_for(config["steps"])

# for _ in range(config["steps"]):
# model.step()
# time.sleep(0.0001)
end_run = timeit.default_timer()

Expand Down
4 changes: 4 additions & 0 deletions mesa/experimental/devs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .eventlist import Priority, SimulationEvent
from .simulator import ABMSimulator, DEVSimulator

__all__ = ["ABMSimulator", "DEVSimulator", "SimulationEvent", "Priority"]
Loading