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

Bugfixes to DEVS #2478

Merged
merged 31 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
87e064e
switch to devs based wolf-sheep
quaquel Nov 8, 2024
16d7b7b
bug fixes in devs
quaquel Nov 8, 2024
2f9928e
add simulator controller
quaquel Nov 8, 2024
83e9f3c
Update wolf_sheep.py
quaquel Nov 8, 2024
1cebacf
testing
quaquel Nov 8, 2024
e49aa0b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 8, 2024
950f2b5
Merge branch 'main' into devs_solara
quaquel Nov 8, 2024
02e5eb4
docstring
quaquel Nov 8, 2024
03b6aeb
Merge branch 'main' into devs_solara
quaquel Nov 9, 2024
d32048b
ongoing
quaquel Nov 9, 2024
d15be56
remove monekypatch of step
quaquel Nov 9, 2024
465691b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2024
e5f1f95
Merge branch 'main' into devs_solara
quaquel Nov 9, 2024
e0deb8d
Merge branch 'main' into devs_solara
quaquel Nov 9, 2024
d8d59f1
devs related updates
quaquel Nov 9, 2024
3c1ac7a
updates
quaquel Nov 9, 2024
8053c0e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2024
6f37e67
cleanup
quaquel Nov 9, 2024
10dfb5e
Update test_examples.py
quaquel Nov 9, 2024
2d09ccc
update benchmarks to reflect new devs usage
quaquel Nov 9, 2024
5b68291
updates
quaquel Nov 9, 2024
1948ba8
cleanup
quaquel Nov 9, 2024
77ede5f
Merge remote-tracking branch 'upstream/main' into devs_solara
quaquel Nov 9, 2024
4808be0
initial commit
quaquel Nov 9, 2024
1cc17b2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2024
78b1dfc
Update solara_viz.py
quaquel Nov 9, 2024
3022ba9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2024
b9b1de5
Update solara_viz.py
quaquel Nov 9, 2024
93d1e3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 9, 2024
29479ee
Update test_examples.py
quaquel Nov 9, 2024
835b985
rename step to run_next_event
quaquel Nov 9, 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
1 change: 0 additions & 1 deletion benchmarks/global_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def run_model(model_class, seed, parameters):
if model_class.__name__ in uses_simulator:
simulator = ABMSimulator()
model = model_class(simulator=simulator, seed=seed, **parameters)
simulator.setup(model)
else:
model = model_class(seed=seed, **parameters)

Expand Down
3 changes: 2 additions & 1 deletion mesa/examples/advanced/wolf_sheep/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ def __init__(
simulator: ABMSimulator instance for event scheduling
"""
super().__init__(seed=seed)
self.simulator = simulator
self.simulator.setup(self)

# Initialize model parameters
self.height = height
self.width = width
self.grass = grass
self.simulator = simulator

# Create grid using experimental cell space
self.grid = OrthogonalVonNeumannGrid(
Expand Down
73 changes: 59 additions & 14 deletions mesa/experimental/devs/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,20 @@ def setup(self, model: Model) -> None:
Args:
model (Model): The model to simulate

Raises:
Exception if simulator.time is not equal to simulator.starttime
Exception if event list is not empty

"""
self.event_list.clear()
if self.time != self.start_time:
raise ValueError(
"trying to setup model, but current time is not equal to start_time, Has the simulator been reset or freshly initialized?"
)
if not self.event_list.is_empty():
raise ValueError(
"trying to setup model, but events have already been scheduled. Call simulator.setup before any scheduling"
)

self.model = model

def reset(self):
Expand All @@ -68,7 +80,20 @@ def reset(self):
self.time = self.start_time

def run_until(self, end_time: int | float) -> None:
"""Run the simulator until the end time."""
"""Run the simulator until the end time.

Args:
end_time (int | float): The end time for stopping the simulator

Raises:
Exception if simulator.setup() has not yet been called

"""
if self.model is None:
raise Exception(
"simulator has not been setup, call simulator.setup(model) first"
)

while True:
try:
event = self.event_list.pop_event()
Expand All @@ -84,6 +109,26 @@ def run_until(self, end_time: int | float) -> None:
self._schedule_event(event) # reschedule event
break

def run_next_event(self):
"""Execute the next event.

Raises:
Exception if simulator.setup() has not yet been called

"""
if self.model is None:
raise Exception(
"simulator has not been setup, call simulator.setup(model) first"
)

try:
event = self.event_list.pop_event()
except IndexError: # event list is empty
return
else:
self.time = event.time
event.execute()

def run_for(self, time_delta: int | float):
"""Run the simulator for the specified time delta.

Expand All @@ -92,6 +137,7 @@ def run_for(self, time_delta: int | float):
plus the time delta

"""
# fixme, raise initialization error or something like it if model.setup has not been called
end_time = self.time + time_delta
self.run_until(end_time)

Expand Down Expand Up @@ -228,7 +274,7 @@ def setup(self, model):

"""
super().setup(model)
self.schedule_event_now(self.model.step, priority=Priority.HIGH)
self.schedule_event_next_tick(self.model.step, priority=Priority.HIGH)

def check_time_unit(self, time) -> bool:
"""Check whether the time is of the correct unit.
Expand Down Expand Up @@ -277,14 +323,24 @@ def run_until(self, end_time: int) -> None:
Args:
end_time (float| int): The end_time delta. The simulator is until the specified end time

Raises:
Exception if simulator.setup() has not yet been called

"""
if self.model is None:
raise Exception(
"simulator has not been setup, call simulator.setup(model) first"
)

while True:
try:
event = self.event_list.pop_event()
except IndexError:
self.time = end_time
break

# fixme: the alternative would be to wrap model.step with an annotation which
# handles this scheduling.
if event.time <= end_time:
self.time = event.time
if event.fn() == self.model.step:
Expand All @@ -298,17 +354,6 @@ def run_until(self, end_time: int) -> None:
self._schedule_event(event)
break

def run_for(self, time_delta: int):
"""Run the simulator for the specified time delta.

Args:
time_delta (float| int): The time delta. The simulator is run from the current time to the current time
plus the time delta

"""
end_time = self.time + time_delta - 1
self.run_until(end_time)


class DEVSimulator(Simulator):
"""A simulator where the unit of time is a float.
Expand Down
44 changes: 42 additions & 2 deletions tests/test_devs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Tests for experimental Simulator classes."""

from unittest.mock import MagicMock
from unittest.mock import MagicMock, Mock

import pytest

Expand Down Expand Up @@ -55,6 +55,23 @@ def test_devs_simulator():
with pytest.raises(ValueError):
simulator.schedule_event_absolute(fn2, 0.5)

# step
simulator = DEVSimulator()
model = MagicMock(spec=Model)
simulator.setup(model)

fn = MagicMock()
simulator.schedule_event_absolute(fn, 1.0)
simulator.run_next_event()
fn.assert_called_once()
assert simulator.time == 1.0
simulator.run_next_event()
assert simulator.time == 1.0

simulator = DEVSimulator()
with pytest.raises(Exception):
simulator.run_next_event()

# cancel_event
simulator = DEVSimulator()
model = MagicMock(spec=Model)
Expand All @@ -70,6 +87,24 @@ def test_devs_simulator():
assert simulator.model is None
assert simulator.time == 0.0

# run without setup
simulator = DEVSimulator()
with pytest.raises(Exception):
simulator.run_until(10)

# setup with time advanced
simulator = DEVSimulator()
simulator.time = simulator.start_time + 1
model = MagicMock(spec=Model)
with pytest.raises(Exception):
simulator.setup(model)

# setup with event scheduled
simulator = DEVSimulator()
simulator.schedule_event_now(Mock())
with pytest.raises(Exception):
simulator.setup(model)


def test_abm_simulator():
"""Tests abm simulator."""
Expand All @@ -86,7 +121,12 @@ def test_abm_simulator():

simulator.run_for(3)
assert model.step.call_count == 3
assert simulator.time == 2
assert simulator.time == 3

# run without setup
simulator = ABMSimulator()
with pytest.raises(Exception):
simulator.run_until(10)


def test_simulation_event():
Expand Down
3 changes: 1 addition & 2 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,5 @@ def test_wolf_sheep(): # noqa: D103
from mesa.experimental.devs import ABMSimulator

simulator = ABMSimulator()
model = WolfSheep(seed=42, simulator=simulator)
simulator.setup(model)
WolfSheep(seed=42, simulator=simulator)
simulator.run_for(10)
Loading