Mesa 3.0.0a3__tar.gz → 3.0.0a4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Mesa might be problematic. Click here for more details.
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/ISSUE_TEMPLATE/bug-report.md +2 -1
- mesa-3.0.0a4/.github/ISSUE_TEMPLATE/config.yml +5 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.pre-commit-config.yaml +1 -1
- {mesa-3.0.0a3 → mesa-3.0.0a4}/HISTORY.md +53 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/PKG-INFO +2 -1
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/BoltzmannWealth/boltzmann_wealth.py +4 -4
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/Flocking/flocking.py +2 -5
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/Schelling/schelling.py +3 -6
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/WolfSheep/wolf_sheep.py +7 -12
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/conf.py +2 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/index.md +2 -2
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/overview.md +5 -5
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/MoneyModel.py +2 -2
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/visualization_tutorial.ipynb +42 -23
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/__init__.py +1 -1
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/agent.py +92 -19
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/batchrunner.py +3 -0
- mesa-3.0.0a4/mesa/experimental/__init__.py +5 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/cell_agent.py +2 -2
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/devs/examples/epstein_civil_violence.py +6 -10
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/devs/examples/wolf_sheep.py +7 -12
- {mesa-3.0.0a3/mesa/visualization → mesa-3.0.0a4/mesa/experimental}/solara_viz.py +3 -3
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/model.py +24 -19
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/space.py +9 -3
- mesa-3.0.0a4/mesa/visualization/UserParam.py +56 -0
- mesa-3.0.0a4/mesa/visualization/__init__.py +14 -0
- mesa-3.0.0a4/mesa/visualization/components/altair.py +86 -0
- mesa-3.0.0a4/mesa/visualization/components/matplotlib.py +246 -0
- mesa-3.0.0a4/mesa/visualization/solara_viz.py +394 -0
- mesa-3.0.0a4/mesa/visualization/utils.py +7 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/pyproject.toml +1 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_agent.py +123 -32
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_batch_run.py +18 -19
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_cell_space.py +7 -7
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_datacollector.py +4 -12
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_lifespan.py +4 -8
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_model.py +18 -5
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_solara_viz.py +11 -40
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_space.py +17 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_time.py +12 -12
- mesa-3.0.0a3/.github/ISSUE_TEMPLATE/asking-help.md +0 -9
- mesa-3.0.0a3/mesa/experimental/__init__.py +0 -3
- mesa-3.0.0a3/mesa/visualization/__init__.py +0 -3
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.codespellignore +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.coveragerc +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/PULL_REQUEST_TEMPLATE/bug.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/PULL_REQUEST_TEMPLATE/feature.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/dependabot.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/release.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/workflows/benchmarks.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/workflows/build_lint.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.github/workflows/release.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.gitignore +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/.readthedocs.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/CITATION.bib +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/CODE_OF_CONDUCT.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/CONTRIBUTING.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/Dockerfile +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/LICENSE +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/README.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/BoltzmannWealth/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/Flocking/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/Schelling/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/WolfSheep/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/compare_timings.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/configurations.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/benchmarks/global_benchmark.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/codecov.yaml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docker-compose.yml +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/Makefile +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/README.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/api_main.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/batchrunner.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/datacollection.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/experimental.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/init.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/space.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/time.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/apis/visualization.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/best-practices.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/howto.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/Mesa_Screenshot.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/mesa_logo.ico +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/mesa_logo.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/br_ginis.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/dc_endwealth.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/dc_gini.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/dc_oneagent.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/first_hist.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/multirun_hist.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/numpy_grid.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/viz_chart.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/viz_empty.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/viz_greycircles.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/viz_histogram.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/images/tutorial/viz_redcircles.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/make.bat +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/mesa.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/migration_guide.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/packages.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_chart.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_empty.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_greycircles.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_histogram.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_redcircles.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/files/viz_slider.png +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/docs/tutorials/intro_tutorial.ipynb +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/maintenance/fetch_unlabeled_prs.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/cookiecutter.json +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/hooks/post_gen_project.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/{{cookiecutter.snake}}/README.md +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/{{cookiecutter.snake}}/app.pytemplate +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/{{cookiecutter.snake}}/setup.pytemplate +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/model.pytemplate +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/datacollection.py +0 -0
- {mesa-3.0.0a3/mesa/visualization → mesa-3.0.0a4/mesa/experimental}/UserParam.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/cell.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/cell_collection.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/discrete_space.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/grid.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/network.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/cell_space/voronoi.py +0 -0
- {mesa-3.0.0a3/mesa/visualization → mesa-3.0.0a4/mesa/experimental}/components/altair.py +0 -0
- {mesa-3.0.0a3/mesa/visualization → mesa-3.0.0a4/mesa/experimental}/components/matplotlib.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/devs/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/devs/eventlist.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/experimental/devs/simulator.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/main.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mesa/time.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/mypy.ini +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/__init__.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/read_requirements.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_devs.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_end_to_end_viz.sh +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_examples.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_grid.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_import_namespace.py +0 -0
- {mesa-3.0.0a3 → mesa-3.0.0a4}/tests/test_scaffold.py +0 -0
|
@@ -11,7 +11,8 @@ about: Let us know if something is broken on Mesa
|
|
|
11
11
|
<!-- A clear and concise description of what you expected to happen -->
|
|
12
12
|
|
|
13
13
|
**To Reproduce**
|
|
14
|
-
<!-- Steps to reproduce the bug, or a link to a project where the bug is visible
|
|
14
|
+
<!-- Steps to reproduce the bug, or a link to a project where the bug is visible
|
|
15
|
+
Include a Minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example -->
|
|
15
16
|
|
|
16
17
|
**Additional context**
|
|
17
18
|
<!--
|
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Release History
|
|
3
3
|
---
|
|
4
|
+
# 3.0.0a4 (2024-09-09)
|
|
5
|
+
## Highlights
|
|
6
|
+
Mesa 3.0.0a4 contains two major breaking changes:
|
|
7
|
+
1. The Agent's `unique_id` is now automatically assigned, so doesn't need to be passed to the Agent class anymore. In a subclassed custom Agent, like normally used, this now looks like this:
|
|
8
|
+
```diff
|
|
9
|
+
class Wolf(Agent):
|
|
10
|
+
- def __init__(self, unique_id, model, energy=None):
|
|
11
|
+
+ def __init__(self, model, energy=None):
|
|
12
|
+
# When initializing the super class (Agent), passing unique_id isn't needed anymore
|
|
13
|
+
- super().__init__(unique_id, model)
|
|
14
|
+
+ super().__init__(model)
|
|
15
|
+
|
|
16
|
+
- wolf = Wolf(unique_id, model)
|
|
17
|
+
+ wolf = Wolf(model)
|
|
18
|
+
```
|
|
19
|
+
Example models were updated in [mesa-examples#194](https://github.com/projectmesa/mesa-examples/pull/194), which shows more examples on how to update existing models.
|
|
20
|
+
|
|
21
|
+
2. Our visualisation API is being overhauled, to be more flexible and powerful. For more details, see [#2278](https://github.com/projectmesa/mesa/pull/2278).
|
|
22
|
+
- An initial update to the tutorial was made in [#2289](https://github.com/projectmesa/mesa/pull/2289) and is [available here](https://mesa.readthedocs.io/en/latest/tutorials/visualization_tutorial.html).
|
|
23
|
+
- An initial example model was updated in [mesa-examples#195](https://github.com/projectmesa/mesa-examples/pull/195), and more examples will be updated in [mesa-examples#195](https://github.com/projectmesa/mesa-examples/pull/193).
|
|
24
|
+
- The old SolaraViz API is still available at `mesa.experimental`, but might be removed in future releases.
|
|
25
|
+
|
|
26
|
+
Furthermore, the AgentSet has a new `agg` method to quickly get an aggerate value (for example `min_energy = model.agents.agg("energy", min)`) ([#2266](https://github.com/projectmesa/mesa/pull/2266)), The Model `get_agents_of_type` function is replaced by directly exposing the `agents_by_type` property (which can be accessed as a dict) ([#2267](https://github.com/projectmesa/mesa/pull/2267), [mesa-examples#190](https://github.com/projectmesa/mesa-examples/pull/190)) and the AgentSet get() methods can now handle missing values by replacing it with a default value ([#2279](https://github.com/projectmesa/mesa/pull/2279)).
|
|
27
|
+
|
|
28
|
+
Finally, it fixes a bug in which the Grid's `move_agent_to_one_of` method with `selection="closest"` selected a location deterministically, instead of randomly ([#2118](https://github.com/projectmesa/mesa/pull/2118)).
|
|
29
|
+
|
|
30
|
+
## What's Changed
|
|
31
|
+
### ⚠️ Breaking changes
|
|
32
|
+
* move solara_viz back to experimental by @Corvince in https://github.com/projectmesa/mesa/pull/2278
|
|
33
|
+
* track unique_id automatically by @quaquel in https://github.com/projectmesa/mesa/pull/2260
|
|
34
|
+
### 🎉 New features added
|
|
35
|
+
* AgentSet: Add `agg` method by @EwoutH in https://github.com/projectmesa/mesa/pull/2266
|
|
36
|
+
* Implement new SolaraViz API by @Corvince in https://github.com/projectmesa/mesa/pull/2263
|
|
37
|
+
### 🛠 Enhancements made
|
|
38
|
+
* Model: Replace `get_agents_of_type` method with `agents_by_type` property by @EwoutH in https://github.com/projectmesa/mesa/pull/2267
|
|
39
|
+
* add default SolaraViz by @Corvince in https://github.com/projectmesa/mesa/pull/2280
|
|
40
|
+
* Simplify ModelController by @Corvince in https://github.com/projectmesa/mesa/pull/2282
|
|
41
|
+
* Add default values and missing value handling to `agentset.get` by @quaquel in https://github.com/projectmesa/mesa/pull/2279
|
|
42
|
+
### 🐛 Bugs fixed
|
|
43
|
+
* Fix deterministic behavior in `move_agent_to_one_of` with `selection="closest"` by @OrenBochman in https://github.com/projectmesa/mesa/pull/2118
|
|
44
|
+
### 📜 Documentation improvements
|
|
45
|
+
* docs: Fix Visualization Tutorial (main branch) by @EwoutH in https://github.com/projectmesa/mesa/pull/2271
|
|
46
|
+
* Docs: Fix broken relative links by removing `.html` suffix by @EwoutH in https://github.com/projectmesa/mesa/pull/2274
|
|
47
|
+
* Readthedocs: Don't let notebook failures pass silently by @EwoutH in https://github.com/projectmesa/mesa/pull/2276
|
|
48
|
+
* Update viz tutorial to the new API by @Corvince in https://github.com/projectmesa/mesa/pull/2289
|
|
49
|
+
### 🔧 Maintenance
|
|
50
|
+
* Resolve multiprocessing warning, state Python 3.13 support by @rht in https://github.com/projectmesa/mesa/pull/2246
|
|
51
|
+
|
|
52
|
+
## New Contributors
|
|
53
|
+
* @OrenBochman made their first contribution in https://github.com/projectmesa/mesa/pull/2118
|
|
54
|
+
|
|
55
|
+
**Full Changelog**: https://github.com/projectmesa/mesa/compare/v3.0.0a3...v3.0.0a4
|
|
56
|
+
|
|
4
57
|
# 3.0.0a3 (2024-08-30)
|
|
5
58
|
## Highlights
|
|
6
59
|
Developments toward Mesa 3.0 are steaming ahead, and our fourth alpha release is packed with features and updates - only 8 days after our third.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: Mesa
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a4
|
|
4
4
|
Summary: Agent-based modeling (ABM) in Python
|
|
5
5
|
Project-URL: homepage, https://github.com/projectmesa/mesa
|
|
6
6
|
Project-URL: repository, https://github.com/projectmesa/mesa
|
|
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
21
|
Classifier: Topic :: Scientific/Engineering
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
23
|
Classifier: Topic :: Scientific/Engineering :: Artificial Life
|
|
@@ -27,8 +27,8 @@ class BoltzmannWealth(mesa.Model):
|
|
|
27
27
|
model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}
|
|
28
28
|
)
|
|
29
29
|
# Create agents
|
|
30
|
-
for
|
|
31
|
-
a = MoneyAgent(
|
|
30
|
+
for _ in range(self.num_agents):
|
|
31
|
+
a = MoneyAgent(self)
|
|
32
32
|
# Add the agent to a random grid cell
|
|
33
33
|
x = self.random.randrange(self.grid.width)
|
|
34
34
|
y = self.random.randrange(self.grid.height)
|
|
@@ -50,8 +50,8 @@ class BoltzmannWealth(mesa.Model):
|
|
|
50
50
|
class MoneyAgent(mesa.Agent):
|
|
51
51
|
"""An agent with fixed initial wealth."""
|
|
52
52
|
|
|
53
|
-
def __init__(self,
|
|
54
|
-
super().__init__(
|
|
53
|
+
def __init__(self, model):
|
|
54
|
+
super().__init__(model)
|
|
55
55
|
self.wealth = 1
|
|
56
56
|
|
|
57
57
|
def move(self):
|
|
@@ -27,7 +27,6 @@ class Boid(mesa.Agent):
|
|
|
27
27
|
|
|
28
28
|
def __init__(
|
|
29
29
|
self,
|
|
30
|
-
unique_id,
|
|
31
30
|
model,
|
|
32
31
|
speed,
|
|
33
32
|
direction,
|
|
@@ -41,7 +40,6 @@ class Boid(mesa.Agent):
|
|
|
41
40
|
Create a new Boid flocker agent.
|
|
42
41
|
|
|
43
42
|
Args:
|
|
44
|
-
unique_id: Unique agent identifier.
|
|
45
43
|
speed: Distance to move per step.
|
|
46
44
|
direction: numpy vector for the Boid's direction of movement.
|
|
47
45
|
vision: Radius to look around for nearby Boids.
|
|
@@ -51,7 +49,7 @@ class Boid(mesa.Agent):
|
|
|
51
49
|
match: the relative importance of matching neighbors' directions
|
|
52
50
|
|
|
53
51
|
"""
|
|
54
|
-
super().__init__(
|
|
52
|
+
super().__init__(model)
|
|
55
53
|
self.speed = speed
|
|
56
54
|
self.direction = direction
|
|
57
55
|
self.vision = vision
|
|
@@ -131,13 +129,12 @@ class BoidFlockers(mesa.Model):
|
|
|
131
129
|
"match": match,
|
|
132
130
|
}
|
|
133
131
|
|
|
134
|
-
for
|
|
132
|
+
for _ in range(self.population):
|
|
135
133
|
x = self.random.random() * self.space.x_max
|
|
136
134
|
y = self.random.random() * self.space.y_max
|
|
137
135
|
pos = np.array((x, y))
|
|
138
136
|
direction = np.random.random(2) * 2 - 1
|
|
139
137
|
boid = Boid(
|
|
140
|
-
unique_id=i,
|
|
141
138
|
model=self,
|
|
142
139
|
speed=speed,
|
|
143
140
|
direction=direction,
|
|
@@ -8,15 +8,14 @@ class SchellingAgent(CellAgent):
|
|
|
8
8
|
Schelling segregation agent
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
def __init__(self,
|
|
11
|
+
def __init__(self, model, agent_type, radius, homophily):
|
|
12
12
|
"""
|
|
13
13
|
Create a new Schelling agent.
|
|
14
14
|
Args:
|
|
15
|
-
unique_id: Unique identifier for the agent.
|
|
16
15
|
x, y: Agent initial location.
|
|
17
16
|
agent_type: Indicator for the agent's type (minority=1, majority=0)
|
|
18
17
|
"""
|
|
19
|
-
super().__init__(
|
|
18
|
+
super().__init__(model)
|
|
20
19
|
self.type = agent_type
|
|
21
20
|
self.radius = radius
|
|
22
21
|
self.homophily = homophily
|
|
@@ -81,9 +80,7 @@ class Schelling(Model):
|
|
|
81
80
|
for cell in self.grid:
|
|
82
81
|
if self.random.random() < density:
|
|
83
82
|
agent_type = 1 if self.random.random() < self.minority_pc else 0
|
|
84
|
-
agent = SchellingAgent(
|
|
85
|
-
self.next_id(), self, agent_type, radius, homophily
|
|
86
|
-
)
|
|
83
|
+
agent = SchellingAgent(self, agent_type, radius, homophily)
|
|
87
84
|
agent.move_to(cell)
|
|
88
85
|
self.schedule.add(agent)
|
|
89
86
|
|
|
@@ -17,8 +17,8 @@ from mesa.experimental.devs import ABMSimulator
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class Animal(CellAgent):
|
|
20
|
-
def __init__(self,
|
|
21
|
-
super().__init__(
|
|
20
|
+
def __init__(self, model, energy, p_reproduce, energy_from_food):
|
|
21
|
+
super().__init__(model)
|
|
22
22
|
self.energy = energy
|
|
23
23
|
self.p_reproduce = p_reproduce
|
|
24
24
|
self.energy_from_food = energy_from_food
|
|
@@ -29,7 +29,6 @@ class Animal(CellAgent):
|
|
|
29
29
|
def spawn_offspring(self):
|
|
30
30
|
self.energy /= 2
|
|
31
31
|
offspring = self.__class__(
|
|
32
|
-
self.model.next_id(),
|
|
33
32
|
self.model,
|
|
34
33
|
self.energy,
|
|
35
34
|
self.p_reproduce,
|
|
@@ -107,7 +106,7 @@ class GrassPatch(CellAgent):
|
|
|
107
106
|
function_args=[self, "fully_grown", True],
|
|
108
107
|
)
|
|
109
108
|
|
|
110
|
-
def __init__(self,
|
|
109
|
+
def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
|
|
111
110
|
"""
|
|
112
111
|
TODO:: fully grown can just be an int --> so one less param (i.e. countdown)
|
|
113
112
|
|
|
@@ -119,7 +118,7 @@ class GrassPatch(CellAgent):
|
|
|
119
118
|
grass_regrowth_time : time to fully regrow grass
|
|
120
119
|
countdown : Time for the patch of grass to be fully regrown if fully grown is False
|
|
121
120
|
"""
|
|
122
|
-
super().__init__(
|
|
121
|
+
super().__init__(model)
|
|
123
122
|
self._fully_grown = fully_grown
|
|
124
123
|
self.grass_regrowth_time = grass_regrowth_time
|
|
125
124
|
|
|
@@ -189,7 +188,6 @@ class WolfSheep(Model):
|
|
|
189
188
|
)
|
|
190
189
|
energy = self.random.randrange(2 * sheep_gain_from_food)
|
|
191
190
|
sheep = Sheep(
|
|
192
|
-
self.next_id(),
|
|
193
191
|
self,
|
|
194
192
|
energy,
|
|
195
193
|
sheep_reproduce,
|
|
@@ -205,7 +203,6 @@ class WolfSheep(Model):
|
|
|
205
203
|
)
|
|
206
204
|
energy = self.random.randrange(2 * wolf_gain_from_food)
|
|
207
205
|
wolf = Wolf(
|
|
208
|
-
self.next_id(),
|
|
209
206
|
self,
|
|
210
207
|
energy,
|
|
211
208
|
wolf_reproduce,
|
|
@@ -221,14 +218,12 @@ class WolfSheep(Model):
|
|
|
221
218
|
countdown = grass_regrowth_time
|
|
222
219
|
else:
|
|
223
220
|
countdown = self.random.randrange(grass_regrowth_time)
|
|
224
|
-
patch = GrassPatch(
|
|
225
|
-
self.next_id(), self, fully_grown, countdown, grass_regrowth_time
|
|
226
|
-
)
|
|
221
|
+
patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
|
|
227
222
|
patch.move_to(cell)
|
|
228
223
|
|
|
229
224
|
def step(self):
|
|
230
|
-
self.
|
|
231
|
-
self.
|
|
225
|
+
self.agents_by_type[Sheep].shuffle(inplace=True).do("step")
|
|
226
|
+
self.agents_by_type[Wolf].shuffle(inplace=True).do("step")
|
|
232
227
|
|
|
233
228
|
|
|
234
229
|
if __name__ == "__main__":
|
|
@@ -113,6 +113,8 @@ pygments_style = "gruvbox-dark"
|
|
|
113
113
|
|
|
114
114
|
nb_execution_timeout = 60
|
|
115
115
|
nb_execution_mode = "cache"
|
|
116
|
+
nb_execution_allow_errors = False
|
|
117
|
+
nb_execution_raise_on_error = True
|
|
116
118
|
|
|
117
119
|
# -- Options for HTML output ----------------------------------------------
|
|
118
120
|
|
|
@@ -99,7 +99,7 @@ Mesa Packages <packages>
|
|
|
99
99
|
[github issue tracker]: https://github.com/projectmesa/mesa/issues
|
|
100
100
|
[matrix chat room]: https://matrix.to/#/#project-mesa:matrix.org
|
|
101
101
|
[mesa]: https://github.com/projectmesa/mesa/
|
|
102
|
-
[mesa introductory tutorial]: tutorials/intro_tutorial
|
|
103
|
-
[mesa visualization tutorial]: tutorials/visualization_tutorial
|
|
102
|
+
[mesa introductory tutorial]: tutorials/intro_tutorial
|
|
103
|
+
[mesa visualization tutorial]: tutorials/visualization_tutorial
|
|
104
104
|
[pypi]: https://pypi.python.org/pypi/Mesa/
|
|
105
105
|
[ticket]: https://github.com/projectmesa/mesa/issues
|
|
@@ -17,8 +17,8 @@ Mesa is modular, meaning that its modeling, analysis and visualization component
|
|
|
17
17
|
Most models consist of one class to represent the model itself; one class (or more) for agents; a scheduler to handle time (what order the agents act in), and possibly a space for the agents to inhabit and move through. These are implemented in Mesa's modeling modules:
|
|
18
18
|
|
|
19
19
|
- `mesa.Model`, `mesa.Agent`
|
|
20
|
-
- [mesa.time](apis/time
|
|
21
|
-
- [mesa.space](apis/space
|
|
20
|
+
- [mesa.time](apis/time)
|
|
21
|
+
- [mesa.space](apis/space)
|
|
22
22
|
|
|
23
23
|
The skeleton of a model might look like this:
|
|
24
24
|
|
|
@@ -56,7 +56,7 @@ model = MyModel(5)
|
|
|
56
56
|
model.step()
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
You should see agents 0-4, activated in random order. See the [tutorial](tutorials/intro_tutorial
|
|
59
|
+
You should see agents 0-4, activated in random order. See the [tutorial](tutorials/intro_tutorial) or API documentation for more detail on how to add model functionality.
|
|
60
60
|
|
|
61
61
|
To bootstrap a new model install mesa and run `mesa startproject`
|
|
62
62
|
|
|
@@ -64,8 +64,8 @@ To bootstrap a new model install mesa and run `mesa startproject`
|
|
|
64
64
|
|
|
65
65
|
If you're using modeling for research, you'll want a way to collect the data each model run generates. You'll probably also want to run the model multiple times, to see how some output changes with different parameters. Data collection and batch running are implemented in the appropriately-named analysis modules:
|
|
66
66
|
|
|
67
|
-
- [mesa.datacollection](apis/datacollection
|
|
68
|
-
- [mesa.batchrunner](apis/batchrunner
|
|
67
|
+
- [mesa.datacollection](apis/datacollection)
|
|
68
|
+
- [mesa.batchrunner](apis/batchrunner)
|
|
69
69
|
|
|
70
70
|
You'd add a data collector to the model like this:
|
|
71
71
|
|
|
@@ -15,8 +15,8 @@ def compute_gini(model):
|
|
|
15
15
|
class MoneyAgent(mesa.Agent):
|
|
16
16
|
"""An agent with fixed initial wealth."""
|
|
17
17
|
|
|
18
|
-
def __init__(self,
|
|
19
|
-
super().__init__(
|
|
18
|
+
def __init__(self, model):
|
|
19
|
+
super().__init__(model)
|
|
20
20
|
self.wealth = 1
|
|
21
21
|
|
|
22
22
|
def move(self):
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"cell_type": "markdown",
|
|
12
12
|
"metadata": {},
|
|
13
13
|
"source": [
|
|
14
|
-
"*This version of the visualisation tutorial is updated for Mesa 3.0, and works with Mesa `3.0.
|
|
14
|
+
"*This version of the visualisation tutorial is updated for Mesa 3.0, and works with Mesa `3.0.0a4` and above. If you are using Mesa 2.3.x, check out the [stable version](https://mesa.readthedocs.io/en/stable/tutorials/visualization_tutorial.html) of this tutorial on Readthedocs.*\n",
|
|
15
15
|
"\n",
|
|
16
16
|
"**Important:** \n",
|
|
17
17
|
"- If you are just exploring Mesa and want the fastest way to execute the code we recommend executing this tutorial online in a Colab notebook. [](https://colab.research.google.com/github/projectmesa/mesa/blob/main/docs/tutorials/visualization_tutorial.ipynb)\n",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"\n",
|
|
22
22
|
"So far, we've built a model, run it, and analyzed some output afterwards. However, one of the advantages of agent-based models is that we can often watch them run step by step, potentially spotting unexpected patterns, behaviors or bugs, or developing new intuitions, hypotheses, or insights. Other times, watching a model run can explain it to an unfamiliar audience better than static explanations. Like many ABM frameworks, Mesa allows you to create an interactive visualization of the model. In this section we'll walk through creating a visualization using built-in components, and (for advanced users) how to create a new visualization element.\n",
|
|
23
23
|
"\n",
|
|
24
|
-
"First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via the Matplotlib plotting library. Alternatively, you can execute everything inside a
|
|
24
|
+
"First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via the Matplotlib plotting library. Alternatively, you can execute everything inside a notebook environment and display it inline."
|
|
25
25
|
]
|
|
26
26
|
},
|
|
27
27
|
{
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"cell_type": "markdown",
|
|
106
106
|
"metadata": {},
|
|
107
107
|
"source": [
|
|
108
|
-
"Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of
|
|
108
|
+
"Next, we instantiate the visualization object which (by default) displays the grid containing the agents, and timeseries of values computed by the model's data collector. In this example, we specify the Gini coefficient.\n",
|
|
109
109
|
"\n",
|
|
110
110
|
"There are 3 buttons:\n",
|
|
111
111
|
"- the step button, which advances the model by 1 step\n",
|
|
@@ -123,14 +123,19 @@
|
|
|
123
123
|
},
|
|
124
124
|
"outputs": [],
|
|
125
125
|
"source": [
|
|
126
|
-
"from mesa.visualization import SolaraViz\n",
|
|
126
|
+
"from mesa.visualization import SolaraViz, make_plot_measure, make_space_matplotlib\n",
|
|
127
|
+
"\n",
|
|
128
|
+
"# Create initial model instance\n",
|
|
129
|
+
"model1 = BoltzmannWealthModel(50, 10, 10)\n",
|
|
130
|
+
"\n",
|
|
131
|
+
"SpaceGraph = make_space_matplotlib(agent_portrayal)\n",
|
|
132
|
+
"GiniPlot = make_plot_measure(\"Gini\")\n",
|
|
127
133
|
"\n",
|
|
128
134
|
"page = SolaraViz(\n",
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
" name=\"
|
|
133
|
-
" agent_portrayal=agent_portrayal,\n",
|
|
135
|
+
" model1,\n",
|
|
136
|
+
" components=[SpaceGraph, GiniPlot],\n",
|
|
137
|
+
" model_params=model_params,\n",
|
|
138
|
+
" name=\"Boltzmann Wealth Model\",\n",
|
|
134
139
|
")\n",
|
|
135
140
|
"# This is required to render the visualization in the Jupyter notebook\n",
|
|
136
141
|
"page"
|
|
@@ -170,11 +175,10 @@
|
|
|
170
175
|
"outputs": [],
|
|
171
176
|
"source": [
|
|
172
177
|
"page = SolaraViz(\n",
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
" name=\"
|
|
177
|
-
" agent_portrayal=agent_portrayal,\n",
|
|
178
|
+
" model1,\n",
|
|
179
|
+
" components=[SpaceGraph, GiniPlot],\n",
|
|
180
|
+
" model_params=model_params,\n",
|
|
181
|
+
" name=\"Boltzmann Wealth Model\",\n",
|
|
178
182
|
")\n",
|
|
179
183
|
"# This is required to render the visualization in the Jupyter notebook\n",
|
|
180
184
|
"page"
|
|
@@ -202,13 +206,13 @@
|
|
|
202
206
|
"import solara\n",
|
|
203
207
|
"from matplotlib.figure import Figure\n",
|
|
204
208
|
"\n",
|
|
205
|
-
"\n",
|
|
206
|
-
"def
|
|
209
|
+
"@solara.component\n",
|
|
210
|
+
"def Histogram(model):\n",
|
|
207
211
|
" # Note: you must initialize a figure using this method instead of\n",
|
|
208
212
|
" # plt.figure(), for thread safety purpose\n",
|
|
209
213
|
" fig = Figure()\n",
|
|
210
214
|
" ax = fig.subplots()\n",
|
|
211
|
-
" wealth_vals = [agent.wealth for agent in model.
|
|
215
|
+
" wealth_vals = [agent.wealth for agent in model.agents]\n",
|
|
212
216
|
" # Note: you have to use Matplotlib's OOP API instead of plt.hist\n",
|
|
213
217
|
" # because plt.hist is not thread-safe.\n",
|
|
214
218
|
" ax.hist(wealth_vals, bins=10)\n",
|
|
@@ -219,7 +223,23 @@
|
|
|
219
223
|
"cell_type": "markdown",
|
|
220
224
|
"metadata": {},
|
|
221
225
|
"source": [
|
|
222
|
-
"
|
|
226
|
+
"In a notebook environment we can directly display the visualization by calling it with the model instance"
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"cell_type": "code",
|
|
231
|
+
"execution_count": null,
|
|
232
|
+
"metadata": {},
|
|
233
|
+
"outputs": [],
|
|
234
|
+
"source": [
|
|
235
|
+
"Histogram(model1)"
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"cell_type": "markdown",
|
|
240
|
+
"metadata": {},
|
|
241
|
+
"source": [
|
|
242
|
+
"Next, we update our solara frontend to use this new component"
|
|
223
243
|
]
|
|
224
244
|
},
|
|
225
245
|
{
|
|
@@ -229,11 +249,10 @@
|
|
|
229
249
|
"outputs": [],
|
|
230
250
|
"source": [
|
|
231
251
|
"page = SolaraViz(\n",
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
" name=\"
|
|
236
|
-
" agent_portrayal=agent_portrayal,\n",
|
|
252
|
+
" model1,\n",
|
|
253
|
+
" components=[SpaceGraph, GiniPlot, Histogram],\n",
|
|
254
|
+
" model_params=model_params,\n",
|
|
255
|
+
" name=\"Boltzmann Wealth Model\",\n",
|
|
237
256
|
")\n",
|
|
238
257
|
"# This is required to render the visualization in the Jupyter notebook\n",
|
|
239
258
|
"page"
|
|
@@ -24,7 +24,7 @@ __all__ = [
|
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
__title__ = "mesa"
|
|
27
|
-
__version__ = "3.0.
|
|
27
|
+
__version__ = "3.0.0a4"
|
|
28
28
|
__license__ = "Apache 2.0"
|
|
29
29
|
_this_year = datetime.datetime.now(tz=datetime.timezone.utc).date().year
|
|
30
30
|
__copyright__ = f"Copyright {_this_year} Project Mesa Team"
|
|
@@ -10,6 +10,8 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import contextlib
|
|
12
12
|
import copy
|
|
13
|
+
import functools
|
|
14
|
+
import itertools
|
|
13
15
|
import operator
|
|
14
16
|
import warnings
|
|
15
17
|
import weakref
|
|
@@ -18,7 +20,7 @@ from collections.abc import Callable, Iterable, Iterator, MutableSet, Sequence
|
|
|
18
20
|
from random import Random
|
|
19
21
|
|
|
20
22
|
# mypy
|
|
21
|
-
from typing import TYPE_CHECKING, Any
|
|
23
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
22
24
|
|
|
23
25
|
if TYPE_CHECKING:
|
|
24
26
|
# We ensure that these are not imported during runtime to prevent cyclic
|
|
@@ -32,21 +34,49 @@ class Agent:
|
|
|
32
34
|
Base class for a model agent in Mesa.
|
|
33
35
|
|
|
34
36
|
Attributes:
|
|
35
|
-
unique_id (int): A unique identifier for this agent.
|
|
36
37
|
model (Model): A reference to the model instance.
|
|
37
|
-
|
|
38
|
+
unique_id (int): A unique identifier for this agent.
|
|
39
|
+
pos (Position): A reference to the position where this agent is located.
|
|
40
|
+
|
|
41
|
+
Notes:
|
|
42
|
+
unique_id is unique relative to a model instance and starts from 1
|
|
43
|
+
|
|
38
44
|
"""
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
# this is a class level attribute
|
|
47
|
+
# it is a dictionary, indexed by model instance
|
|
48
|
+
# so, unique_id is unique relative to a model, and counting starts from 1
|
|
49
|
+
_ids = defaultdict(functools.partial(itertools.count, 1))
|
|
50
|
+
|
|
51
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
41
52
|
"""
|
|
42
53
|
Create a new agent.
|
|
43
54
|
|
|
44
55
|
Args:
|
|
45
|
-
unique_id (int): A unique identifier for this agent.
|
|
46
56
|
model (Model): The model instance in which the agent exists.
|
|
47
57
|
"""
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
# TODO: Cleanup in future Mesa version (3.1+)
|
|
59
|
+
match args:
|
|
60
|
+
# Case 1: Only the model is provided. The new correct behavior.
|
|
61
|
+
case [model]:
|
|
62
|
+
self.model = model
|
|
63
|
+
self.unique_id = next(self._ids[model])
|
|
64
|
+
# Case 2: Both unique_id and model are provided, deprecated
|
|
65
|
+
case [_, model]:
|
|
66
|
+
warnings.warn(
|
|
67
|
+
"unique ids are assigned automatically to Agents in Mesa 3. The use of custom unique_id is "
|
|
68
|
+
"deprecated. Only input a model when calling `super()__init__(model)`. The unique_id inputted is not used.",
|
|
69
|
+
DeprecationWarning,
|
|
70
|
+
stacklevel=2,
|
|
71
|
+
)
|
|
72
|
+
self.model = model
|
|
73
|
+
self.unique_id = next(self._ids[model])
|
|
74
|
+
# Case 3: Anything else, raise an error
|
|
75
|
+
case _:
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"Invalid arguments provided to initialize the Agent. Only input a model: `super()__init__(model)`."
|
|
78
|
+
)
|
|
79
|
+
|
|
50
80
|
self.pos: Position | None = None
|
|
51
81
|
|
|
52
82
|
self.model.register_agent(self)
|
|
@@ -304,29 +334,72 @@ class AgentSet(MutableSet, Sequence):
|
|
|
304
334
|
|
|
305
335
|
return res
|
|
306
336
|
|
|
307
|
-
def
|
|
337
|
+
def agg(self, attribute: str, func: Callable) -> Any:
|
|
338
|
+
"""
|
|
339
|
+
Aggregate an attribute of all agents in the AgentSet using a specified function.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
attribute (str): The name of the attribute to aggregate.
|
|
343
|
+
func (Callable): The function to apply to the attribute values (e.g., min, max, sum, np.mean).
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Any: The result of applying the function to the attribute values. Often a single value.
|
|
347
|
+
"""
|
|
348
|
+
values = self.get(attribute)
|
|
349
|
+
return func(values)
|
|
350
|
+
|
|
351
|
+
def get(
|
|
352
|
+
self,
|
|
353
|
+
attr_names: str | list[str],
|
|
354
|
+
handle_missing: Literal["error", "default"] = "error",
|
|
355
|
+
default_value: Any = None,
|
|
356
|
+
) -> list[Any] | list[list[Any]]:
|
|
308
357
|
"""
|
|
309
358
|
Retrieve the specified attribute(s) from each agent in the AgentSet.
|
|
310
359
|
|
|
311
360
|
Args:
|
|
312
361
|
attr_names (str | list[str]): The name(s) of the attribute(s) to retrieve from each agent.
|
|
362
|
+
handle_missing (str, optional): How to handle missing attributes. Can be:
|
|
363
|
+
- 'error' (default): raises an AttributeError if attribute is missing.
|
|
364
|
+
- 'default': returns the specified default_value.
|
|
365
|
+
default_value (Any, optional): The default value to return if 'handle_missing' is set to 'default'
|
|
366
|
+
and the agent does not have the attribute.
|
|
313
367
|
|
|
314
368
|
Returns:
|
|
315
|
-
list[Any]: A list with the attribute value for each agent
|
|
316
|
-
list[list[Any]]: A list with a
|
|
369
|
+
list[Any]: A list with the attribute value for each agent if attr_names is a str.
|
|
370
|
+
list[list[Any]]: A list with a lists of attribute values for each agent if attr_names is a list of str.
|
|
317
371
|
|
|
318
372
|
Raises:
|
|
319
|
-
AttributeError
|
|
320
|
-
|
|
321
|
-
"""
|
|
373
|
+
AttributeError: If 'handle_missing' is 'error' and the agent does not have the specified attribute(s).
|
|
374
|
+
ValueError: If an unknown 'handle_missing' option is provided.
|
|
375
|
+
"""
|
|
376
|
+
is_single_attr = isinstance(attr_names, str)
|
|
377
|
+
|
|
378
|
+
if handle_missing == "error":
|
|
379
|
+
if is_single_attr:
|
|
380
|
+
return [getattr(agent, attr_names) for agent in self._agents]
|
|
381
|
+
else:
|
|
382
|
+
return [
|
|
383
|
+
[getattr(agent, attr) for attr in attr_names]
|
|
384
|
+
for agent in self._agents
|
|
385
|
+
]
|
|
386
|
+
|
|
387
|
+
elif handle_missing == "default":
|
|
388
|
+
if is_single_attr:
|
|
389
|
+
return [
|
|
390
|
+
getattr(agent, attr_names, default_value) for agent in self._agents
|
|
391
|
+
]
|
|
392
|
+
else:
|
|
393
|
+
return [
|
|
394
|
+
[getattr(agent, attr, default_value) for attr in attr_names]
|
|
395
|
+
for agent in self._agents
|
|
396
|
+
]
|
|
322
397
|
|
|
323
|
-
if isinstance(attr_names, str):
|
|
324
|
-
return [getattr(agent, attr_names) for agent in self._agents]
|
|
325
398
|
else:
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
399
|
+
raise ValueError(
|
|
400
|
+
f"Unknown handle_missing option: {handle_missing}, "
|
|
401
|
+
"should be one of 'error' or 'default'"
|
|
402
|
+
)
|
|
330
403
|
|
|
331
404
|
def set(self, attr_name: str, value: Any) -> AgentSet:
|
|
332
405
|
"""
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import itertools
|
|
2
|
+
import multiprocessing
|
|
2
3
|
from collections.abc import Iterable, Mapping
|
|
3
4
|
from functools import partial
|
|
4
5
|
from multiprocessing import Pool
|
|
@@ -8,6 +9,8 @@ from tqdm.auto import tqdm
|
|
|
8
9
|
|
|
9
10
|
from mesa.model import Model
|
|
10
11
|
|
|
12
|
+
multiprocessing.set_start_method("spawn", force=True)
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
def batch_run(
|
|
13
16
|
model_cls: type[Model],
|