-
Notifications
You must be signed in to change notification settings - Fork 874
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
Conversation
for more information, see https://pre-commit.ci
This looks like an remarkable effort. I will try to review after the weekend. |
The benchmarks are currently failing because they rely on a for loop. I'll have to update all benchmarks to use a simulator. Will probably do this tomorrow. |
Just started to finally look into this, but already want to say great effort and awesome work! I'll have a few questions, but first impression is very good. |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
Performance benchmarks:
|
These benchmarks ❤️! Do you know why the BoidFlockers initialization is so much faster? I will try to review tomorrow. |
This branch was not up to date with main, so something in main should explain that. My hunch is that it is #2083. |
for more information, see https://pre-commit.ci
This is amazing! The only real block I really saw was the merge conflict so I resolved the merge conflict in flockers benchmark. As Ewout, rht and Corvince have all reviewed this, I don't think I will provide any more value added. I would ask one of them to do the actual merge if they are good with it and then per the dev session we can release 2.3.0. |
I am meeting with @EwoutH in a bit. I'll discuss the PR and any possible open issues. |
I think the only thing that needed to be done was to remove the old DiscreteEventScheduler and put a warning there, right? |
That is the most important thing indeed. I might have some time over the weekend to finalize this. |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
|
# Summary This PR adds an experiment feature that puts event scheduling at the heart of how MESA works. An earlier draft of this code was shown and discussed in projectmesa#2032. This code generalizes projectmesa#1890 by making discrete event scheduling central to how mesa models are run. This makes it trivial to maintain discrete time progression while allowing for event scheduling, thus making it possible to build hybrid ABM-DEVS models. # Motive Agent-based models can be quite slow because, typically, they involve the activation of all agents at each tick. However, this can become very expensive if it can be known upfront that the agent is not active. Combining ABM tick-based activation with event scheduling makes it easy to avoid activating dormant agents. For example, in Epstein's civil violence model, agents who are in jail need not be activated until they are released from jail. This release from jail can be scheduled as an event, thus avoiding unnecessary agent activations. Likewise, in Wolf-Sheep with grass, the regrowth of grass patches can be scheduled instead of activating all patches for each tick only to decrement a counter. # Implementation The experimental feature adds three core new classes: Simulator, EventList, and SimulationEvent. The simulator is analogous to a numerical solver for ODEs. Theoretically, the idea of a Simulator is rooted in the work of [Zeigler](https://www.sciencedirect.com/book/9780128133705/theory-of-modeling-and-simulation), The Simulator is responsible for controlling and advancing time. The EventList is a heapq sorted list of SimulationEvents. SimulationEvents are sorted based on their time of execution, their priority, and their unique_id. A SimulationEvent is, in essence, a callable that is to be executed at a particular simulation time instant. This PR adds two specific simulators: ABMSimulator and DEVSSimulator. ABMSimulator uses integers as the base unit of time and automatically ensures that `model.step` is scheduled for each tick. DEVSSimulator uses float as the base unit of time. It allows for full discrete event scheduling. Using these new classes requires a minor modification to a Model instance. It needs a simulator attribute to be able to schedule events. # Usage The basic usage is straightforward as shown below. We instantiate an ABMSimulator, instantiate the model, and call `simulator.setup`. Next, we can run the model for, e.g., 100 time steps). ```python simulator = ABMSimulator() model = WolfSheep(simulator,25, 25, 60, 40, 0.2, 0.1, 20, seed=15,) simulator.setup(model) simulator.run(100) print(model.time) # prints 100 simulator.run(50) print(model.time) # prints 150 ``` The simulator comes with a whole range of methods for scheduling events: `schedule_event_now`, `schedule_event_relative`, `schedule_event_absolute`, and the ABMSimulator also has a `schedule_event_next_tick`. See `experimental/devs/examples/*.*` for more details on how to use these methods.
@quaquel in my model I'm doing: simulator1 = DEVSimulator()
model1 = UrbanModel(n_agents=5, simulator=simulator1)
simulator1.setup(model1) In the initialisation the first events are scheduled. However, when I then do mesa/mesa/experimental/devs/simulator.py Line 48 in 1202e2e
Luckily this is quite easily circumvented by replacing the last line with However, I'm quite afraid most users won't discover this, since all the examples use the
|
Another question: Is simulator time ( |
Running a model multiple times in a row. I also just followed dsol here.
Ideally yes, there should be a common way to reset a model to its initial state. This could be done on the model or the simulator. I need to think whether I have a preference.
Let's first figure out what we want. I personally have in the passed pushed for a model.init and model.reset method. This would avoid the problem you ran into because any event scheduling would go to model.init. So you get something like. simulator = DevsSimulator()
model = myModel()
simulator.setup(model)
model.init()
simulator.run()
I don't recall, so I would need to check the code. In my vision for MESA 3, time should be kept by the simulator, not by the model. |
Thanks for the comments, they are useful and it's good to have this documented. I got it working as need for my model right now, but it also shows it's not directly ready to be stabilized. It requires a few more iterations of building models --> discovering limitations --> implementing feedback --> building models. When you figure out how the internals work it's quite powerful though! |
Summary
This PR adds an experiment feature that puts event scheduling at the heart of how MESA works. An earlier draft of this code was shown and discussed in #2032. This code generalizes #1890 by making discrete event scheduling central to how mesa models are run. This makes it trivial to maintain discrete time progression while allowing for event scheduling, thus making it possible to build hybrid ABM-DEVS models.
Motive
Agent-based models can be quite slow because, typically, they involve the activation of all agents at each tick. However, this can become very expensive if it can be known upfront that the agent is not active. Combining ABM tick-based activation with event scheduling makes it easy to avoid activating dormant agents.
For example, in Epstein's civil violence model, agents who are in jail need not be activated until they are released from jail. This release from jail can be scheduled as an event, thus avoiding unnecessary agent activations. Likewise, in Wolf-Sheep with grass, the regrowth of grass patches can be scheduled instead of activating all patches for each tick only to decrement a counter.
Implementation
The experimental feature adds three core new classes: Simulator, EventList, and SimulationEvent.
The simulator is analogous to a numerical solver for ODEs. Theoretically, the idea of a Simulator is rooted in the work of Zeigler, The Simulator is responsible for controlling and advancing time. The EventList is a heapq sorted list of SimulationEvents. SimulationEvents are sorted based on their time of execution, their priority, and their unique_id. A SimulationEvent is, in essence, a callable that is to be executed at a particular simulation time instant.
This PR adds two specific simulators: ABMSimulator and DEVSSimulator. ABMSimulator uses integers as the base unit of time and automatically ensures that
model.step
is scheduled for each tick. DEVSSimulator uses float as the base unit of time. It allows for full discrete event scheduling.Using these new classes requires a minor modification to a Model instance. It needs a simulator attribute to be able to schedule events.
Usage
The basic usage is straightforward as shown below. We instantiate an ABMSimulator, instantiate the model, and call
simulator.setup
. Next, we can run the model for, e.g., 100 time steps).The simulator comes with a whole range of methods for scheduling events:
schedule_event_now
,schedule_event_relative
,schedule_event_absolute
, and the ABMSimulator also has aschedule_event_next_tick
. Seeexperimental/devs/examples/*.*
for more details on how to use these methods.