Skip to content

Commit

Permalink
Deprecate Time module and all its Schedulers (#2306)
Browse files Browse the repository at this point in the history
As concluded in #2231, this PR deprecates the whole Time module and all its Schedulers. This change aims to provide more flexibility and control in agent activation and time management, inspired by the NetLogo framework.

### Changes
1. Deprecated the entire `mesa.time` module.
2. Added a module-level deprecation warning to `mesa.time`.
3. Updated the migration guide to include instructions for replacing each scheduler with AgentSet functionality.
4. Removed the `tests/test_time.py` file as it's no longer relevant.

### Migration Guide
The migration guide has been updated to include detailed instructions on how to replace each scheduler with AgentSet functionality. This includes examples for:

- BaseScheduler
- RandomActivation
- SimultaneousActivation
- StagedActivation
- RandomActivationByType

The guide also includes general notes on changes to related functionality, such as the automatic incrementing of `Model.steps` and the replacement of scheduler-specific methods with AgentSet methods.
  • Loading branch information
EwoutH committed Sep 21, 2024
1 parent 7d29326 commit a686826
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 302 deletions.
99 changes: 98 additions & 1 deletion docs/migration_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,105 @@ You can access it by `Model.steps`, and it's internally in the datacollector, ba
#### Removal of `Model._advance_time()`
- The `Model._advance_time()` method is removed. This now happens automatically.

<!-- TODO deprecate all schedulers? -->
### Replacing Schedulers with AgentSet functionality
The whole Time module in Mesa is deprecated, and all schedulers are being replaced with AgentSet functionality and the internal `Model.steps` counter. This allows much more flexibility in how to activate Agents and makes it explicit what's done exactly.

Here's how to replace each scheduler:

#### BaseScheduler
Replace:
```python
self.schedule = BaseScheduler(self)
self.schedule.step()
```
With:
```python
self.agents.do("step")
```

#### RandomActivation
Replace:
```python
self.schedule = RandomActivation(self)
self.schedule.step()
```
With:
```python
self.agents.shuffle_do("step")
```

#### SimultaneousActivation
Replace:
```python
self.schedule = SimultaneousActivation(self)
self.schedule.step()
```
With:
```python
self.agents.do("step")
self.agents.do("advance")
```

#### StagedActivation
Replace:
```python
self.schedule = StagedActivation(self, ["stage1", "stage2", "stage3"])
self.schedule.step()
```
With:
```python
for stage in ["stage1", "stage2", "stage3"]:
self.agents.do(stage)
```

If you were using the `shuffle` and/or `shuffle_between_stages` options:
```python
stages = ["stage1", "stage2", "stage3"]
if shuffle:
self.random.shuffle(stages)
for stage in stages:
if shuffle_between_stages:
self.agents.shuffle_do(stage)
else:
self.agents.do(stage)
```

#### RandomActivationByType
Replace:
```python
self.schedule = RandomActivationByType(self)
self.schedule.step()
```
With:
```python
for agent_class in self.agent_types:
self.agents_by_type[agent_class].shuffle_do("step")
```

##### Replacing `step_type`
The `RandomActivationByType` scheduler had a `step_type` method that allowed stepping only agents of a specific type. To replicate this functionality using AgentSet:

Replace:
```python
self.schedule.step_type(AgentType)
```

With:
```python
self.agents_by_type[AgentType].shuffle_do("step")
```

#### General Notes

1. The `Model.steps` counter is now automatically incremented. You don't need to manage it manually.
2. If you were using `self.schedule.agents`, replace it with `self.agents`.
3. If you were using `self.schedule.get_agent_count()`, replace it with `len(self.agents)`.
4. If you were using `self.schedule.agents_by_type`, replace it with `self.agents_by_type`.
5. Instead of `self.schedule.add()` and `self.schedule.remove()`, agents are now automatically added to and removed from the model's AgentSet when they are created or removed.

From now on you're now not bound by 5 distinct schedulers, but can mix and match any combination of AgentSet methods (`do`, `shuffle`, `select`, etc.) to get the desired Agent activation.

Ref: Original discussion [#1912](https://github.com/projectmesa/mesa/discussions/1912), decision discussion [#2231](https://github.com/projectmesa/mesa/discussions/2231), example updates [#183](https://github.com/projectmesa/mesa-examples/pull/183) and [#201](https://github.com/projectmesa/mesa-examples/pull/201), PR [#2306](https://github.com/projectmesa/mesa/pull/2306)

### Visualisation

Expand Down
13 changes: 13 additions & 0 deletions mesa/time.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
"""Mesa Time Module.
.. warning::
The time module and all its Schedulers are deprecated and will be removed in a future version.
They can be replaced with AgentSet functionality. See the migration guide for details:
https://mesa.readthedocs.io/en/latest/migration_guide.html#time-and-schedulers
Objects for handling the time component of a model. In particular, this module
contains Schedulers, which handle agent activation. A Scheduler is an object
which controls when agents are called upon to act, and when.
Expand Down Expand Up @@ -57,6 +62,14 @@ def __init__(self, model: Model, agents: Iterable[Agent] | None = None) -> None:
agents (Iterable[Agent], None, optional): An iterable of agents who are controlled by the schedule
"""
warnings.warn(
"The time module and all its Schedulers are deprecated and will be removed in a future version. "
"They can be replaced with AgentSet functionality. See the migration guide for details. "
"https://mesa.readthedocs.io/en/latest/migration_guide.html#time-and-schedulers",
DeprecationWarning,
stacklevel=2,
)

self.model = model
self.steps = 0
self.time: TimeT = 0
Expand Down
Loading

0 comments on commit a686826

Please sign in to comment.