Skip to content

Commit e3df717

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents c9d3b70 + e9054ad commit e3df717

File tree

5 files changed

+63
-7
lines changed

5 files changed

+63
-7
lines changed

CONTRIBUTING.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,42 @@ All roles are expected to:
177177

178178
Mesa grows through good ideas and contributions. We're all volunteers working together to make Mesa better. Don't hesitate to reach out to any maintainer to discuss your interests and potential growth within the project!
179179

180+
## Mesa examples structure and policy
181+
Mesa maintains a curated set of core examples within the main repository, complemented by a separate [mesa-examples](https://github.com/mesa/mesa-examples) repository for community contributions. This two-tier structure balances maintainability with community creativity.
182+
183+
### Core examples (in `mesa/examples`)
184+
Core examples in the main Mesa repository are classic, well-known agent-based models that demonstrate Mesa's capabilities and serve as learning resources. They are organized into two categories:
185+
186+
- **Basic Examples** use only stable Mesa features and are ideal starting points for beginners.
187+
- **Advanced Examples** are more complex models that may use experimental features to demonstrate advanced concepts.
188+
189+
Core examples are:
190+
- Tested in CI, including batch runs and visualizations
191+
- Maintained to high code quality standards
192+
- Updated to work with each Mesa release
193+
- Documented and included in ReadTheDocs
194+
- Some are used in performance benchmarking
195+
196+
### Community examples (in mesa-examples)
197+
The [mesa-examples](https://github.com/mesa/mesa-examples) repository serves as a gallery for user-contributed models and creative applications of Mesa. We welcome diverse contributions here with more relaxed maintenance requirements. Examples in this repository should include:
198+
- A clear README explaining the model
199+
- Requirements or environment files for reproducibility
200+
- Working code compatible with at least one Mesa major version
201+
202+
We accept contributions liberally to this repository to showcase the breadth of Mesa applications, even if we cannot actively maintain all examples long-term.
203+
204+
### Contributing examples
205+
When contributing a new example, consider:
206+
- **For core examples**: Propose additions through a GitHub discussion first. Core examples should be:
207+
- widely-recognized canonical models
208+
- demonstrate specific Mesa features effectively (that are not already sufficiently demonstrated by other models)
209+
- **For community examples**: Open a PR directly to mesa-examples with your model, README, and environment file.
210+
- **Improving existing examples**: PRs to update or enhance any example are always welcome in either repository.
211+
212+
This structure allows us to maintain a stable, high-quality set of learning resources while encouraging community creativity and diverse applications of Mesa.
213+
214+
Historical context and further motivation can be found in discussion [#2330](https://github.com/mesa/mesa/discussions/2330) and PR [#2349](https://github.com/mesa/mesa/pull/2349).
215+
180216
## Maintainers' notes
181217
Some notes useful for Mesa maintainers.
182218

docs/tutorials/1_adding_space.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@
347347
"source": [
348348
"## Next Steps\n",
349349
"\n",
350-
"Check out the [collecting data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data_tutorial.html) on how to collect data form your model."
350+
"Check out the [collecting data tutorial](https://mesa.readthedocs.io/latest/tutorials/2_collecting_data.html) on how to collect data form your model."
351351
]
352352
},
353353
{

mesa/discrete_space/grid.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _validate_parameters(self):
141141
raise ValueError("Capacity must be a number or None.")
142142

143143
def select_random_empty_cell(self) -> T: # noqa
144-
# FIXME:: currently just a simple boolean to control behavior
144+
# Use a heuristic: try random sampling first for performance (O(1))
145145
# FIXME:: basically if grid is close to 99% full, creating empty list can be faster
146146
# FIXME:: note however that the old results don't apply because in this implementation
147147
# FIXME:: because empties list needs to be rebuild each time
@@ -151,12 +151,14 @@ def select_random_empty_cell(self) -> T: # noqa
151151
# https://github.com/mesa/mesa/pull/1565. The cutoff value provided
152152
# is the break-even comparison with the time taken in the else branching point.
153153
if self._try_random:
154-
while True:
154+
# Limit attempts to avoid infinite loops on full grids
155+
for _ in range(50):
155156
cell = self.all_cells.select_random_cell()
156157
if cell.is_empty:
157158
return cell
158-
else:
159-
return super().select_random_empty_cell()
159+
160+
# Fallback to the robust parent method (O(N)) if random sampling fails
161+
return super().select_random_empty_cell()
160162

161163
def _connect_single_cell_nd(self, cell: T, offsets: list[tuple[int, ...]]) -> None:
162164
coord = cell.coordinate

tests/discrete_space/test_discrete_space.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,3 +1092,21 @@ def test_select_random_agent_empty_safe():
10921092
empty_collection.select_random_agent()
10931093
assert empty_collection.select_random_agent(default=None) is None
10941094
assert empty_collection.select_random_agent(default="Empty") == "Empty"
1095+
1096+
1097+
def test_infinite_loop_on_full_grid():
1098+
"""Test that select_random_empty_cell does not hang on a full grid."""
1099+
# 1. Create a small 2x2 model
1100+
model = Model()
1101+
grid = OrthogonalMooreGrid((2, 2), random=model.random)
1102+
1103+
# 2. Fill the grid completely
1104+
for cell in grid.all_cells:
1105+
agent = CellAgent(model)
1106+
agent.cell = cell
1107+
1108+
# 3. Verify grid is full
1109+
assert len(grid.empties) == 0
1110+
1111+
with pytest.raises(IndexError):
1112+
grid.select_random_empty_cell()

tests/examples/test_examples_viz.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ def run_model_test(
7272
# Display and capture the updated visualizations
7373
display(space_viz)
7474
page_session.wait_for_selector("img")
75-
changed_space = page_session.locator("img").screenshot()
75+
changed_space = page_session.locator("img").first.screenshot()
7676

7777
if measure_config:
7878
display(graph_viz)
7979
page_session.wait_for_selector("img")
80-
changed_graph = page_session.locator("img").screenshot()
80+
changed_graph = page_session.locator("img").last.screenshot()
8181

8282
# Convert screenshots to base64 for comparison
8383
initial_space_encoding = base64.b64encode(initial_space).decode()

0 commit comments

Comments
 (0)