Add event scheduling and time progression API v2#3188
Add event scheduling and time progression API v2#3188
Conversation
Introduces clean scheduling and run control methods directly on Model, providing a unified interface for both traditional time-step advancement and discrete event simulation. New Model methods: - schedule_at(callback, time): Schedule event at absolute time - schedule_after(callback, delay): Schedule event after delay - cancel_event(event): Cancel a scheduled event - run_until(end_time): Run until specific time - run_for(duration): Run for specific duration - run_while(condition): Run while condition is true - run_next_event(): Execute next scheduled event Implementation: - Creates timeflow.py with Scheduler and RunControl classes - Model delegates to internal _scheduler and _run_control instances - Modifies _wrapped_step to use run_for(1) internally - Non-breaking: existing step-based models work unchanged This lays the foundation for more advanced features like recurring methods and agent self-scheduling while maintaining full backward compatibility.
Introduces a @scheduled decorator to mark model methods for automatic recurring scheduling. The Scheduler now detects and schedules these methods at specified intervals and priorities, simplifying periodic event management in Mesa models.
Refactored the @scheduled decorator to support usage with and without parentheses. Updated Model initialization to check for scheduled step methods and avoid double-wrapping. Modified Scheduler to detect scheduled methods from the class definition and properly schedule bound instance methods. Enhanced recurring event scheduling and rescheduling logic in RunControl and Scheduler for more robust simulation event handling.
Introduces a new test suite for the unified time and event scheduling API, covering Scheduler, RunControl, the @scheduled decorator, Model integration, and various edge cases. These tests verify correct event scheduling, priorities, cancellation, model run methods, agent self-scheduling, and error handling.
Introduces the RecurringEvent class to handle events that automatically reschedule themselves after execution. Updates the Scheduler and RunControl logic to use RecurringEvent for scheduled methods, simplifying recurring event management and removing manual rescheduling code.
Added a PendingDeprecationWarning to discourage calling model.step() directly in a loop, guiding users to use the new @scheduled decorator and run methods introduced in Mesa 3.5. Updated the migration guide with detailed instructions and examples for adopting the unified time API.
Replaces direct import of Scheduler with a conditional import under TYPE_CHECKING to avoid runtime dependencies and improve type hinting.
ModelController and SimulatorController now detect if the model uses the new @scheduled API and call run_for(1) instead of step(). This ensures compatibility with both traditional and unified model stepping methods.
Reorganized and consolidated import statements in mesa/experimental/devs/eventlist.py for improved readability and to avoid redundant imports.
Replaces usage of ABMSimulator with direct scheduling via model methods and the @scheduled decorator. Updates agent scheduling and test code to reflect the new approach.
Simplifies the run_model function by removing conditional logic for ABMSimulator and using model.run_for for all models.
We can later decide how to deprecate exactly.
110bc54 to
647affb
Compare
|
Performance benchmarks:
|
|
If you think, +1800 lines of code, what are you smoking?
|
|
I am sorry, but I don't like this API. Notions such as |
|
Thanks for your perspective. It may indeed make sense to split into |
|
Something else: I’m a bit in doubt if |
Good question. The name is clear, but adding methods like start and stop makes it more than just a recurring event. Generator does not really capture this either. So, I don't know yet. |
|
Thanks for the insights. To be continued in: |
Based on the discussions and accumulating insights in #3155 and #2921 (comment), a new implementation that implements the single
schedule()method.Builds on #3155. Can either be directly merged or after #3155 (I recommend former).
What's quite cool is that it schedules a
model.step()event every 1 time. So like a ABMSimulator by default. Like a hearth beat. Can easily be turned off for full DEVS.That also makes it super super backwards compatible.
Design decisions
I started from the following design decisions:
stepis going to be the hearth beat of Mesa. This keeps backwards compatibility and a familiar way for basic models, with the only difference for them being to run a model with run() instead of repeated step calls. Internally, it's just a scheduled function with interval 1, and can be overwritten.model.schedule()method returns theEventorRecurringEventobject directly, which in case of Recurring has methods likepause(),resume(), andcancel()for user control.self.trading = model.schedule(self.trade, interval=1)), while one-off events that don't need later control can ignore the return value.stepmethod is automatically scheduled as aRecurringEventwithinterval=1and stored inself.step_event, making it easy to introspect or modify the model's heartbeat.Methods
Some methods
Return Values
SimulationEventRecurringEventwithpause(),resume(),stop()methodsDefault Step Behavior
Model.__init__automatically schedulesself.stepas aRecurringEventwithinterval=1self.step_eventfor user access/modificationstep()method, the scheduling is automaticConvenience Methods
model.schedule_at(callback, time, ...)→ wrapsschedule(start_at=time)model.schedule_after(callback, delay, ...)→ wrapsschedule(start_after=delay)Run Methods
model.run_for(duration)- run for N time unitsmodel.run_until(end_time)- run until absolute timemodel.run_while(condition)- run while condition is truemodel.run_next_event()- single event execution (debugging)TODO
Follow-up PRs:
(please do not update, rebase or touch my branch in any way)