-
Notifications
You must be signed in to change notification settings - Fork 1k
Open
Labels
bugRelease notes labelRelease notes label
Description
Describe the bug
Hex Grid remove_cell
doesn't clear cache on cells.
I have a simple example where I removing diagonal cells and place agents to separate them. After creating agents I added new cells at same places but without connections. When I run script, I found that some cells uses previous connection before removing cells. I can reproduce this bug at HexGrid.
Workaround
create NoCachedCell and use as cell class
To Reproduce
"""
Simple example demonstrating Mesa's OrthogonalMooreGrid with CellAgent.
This example creates a 5x5 grid where agents can move and interact with neighbors
using the Moore neighborhood (8 surrounding cells).
"""
from random import Random
from typing import Optional, List
import mesa
from mesa.discrete_space import CellAgent, OrthogonalMooreGrid, HexGrid
from mesa.discrete_space.cell import Cell, Coordinate
from mesa.discrete_space.cell_collection import CellCollection
class NoCachedCell(Cell):
@property
def neighborhood(self) -> CellCollection[Cell]:
return self.get_neighborhood()
class MoneyAgent(CellAgent):
"""An agent with fixed initial wealth that can move around the grid."""
def __init__(self, model: "MoneyModel", cell) -> None:
"""
Create a new agent.
Args:
model: Model instance
cell: The cell where this agent is located
"""
super().__init__(model)
self.cell = cell
self.prev_cell = cell
self.wealth = 1
def move(self) -> None:
"""Move to a random cell in the Moore neighborhood."""
try:
prev_cell = self.cell
self.cell = self.cell.neighborhood.select_random_cell()
self.prev_cell = prev_cell
except IndexError as e:
print(self.prev_cell.coordinate, self.cell.coordinate, [c.coordinate for c in self.prev_cell.neighborhood.cells])
raise e
def give_money(self) -> None:
"""Give 1 unit of wealth to another agent in the same cell."""
# Get all agents in the current cell except self
cellmates = [a for a in self.cell.agents if a is not self]
if self.wealth > 0 and cellmates:
other_agent = self.random.choice(cellmates)
other_agent.wealth += 1
self.wealth -= 1
class MoneyModel(mesa.Model):
"""A model with agents moving on a grid and exchanging money."""
def __init__(self, n_agents: int = 10, width: int = 5, height: int = 5, seed: Optional[int] = None) -> None:
"""
Create a new Money Model.
Args:
n_agents: Number of agents to create
width: Width of the grid
height: Height of the grid
seed: Random seed for reproducibility
"""
super().__init__(seed=seed)
self.num_agents = n_agents
# Create grid with Moore neighborhood and allow multiple agents per cell
self.grid = HexGrid(
(width, height),
torus=True, # Wrap around edges
capacity=None, # Max agents per cell
random=self.random,
#cell_klass=NoCachedCell
)
# Remove and add cells to the grid to test the grid
for i in range(width):
self.grid.remove_cell(self.grid[(i, i)])
# Create agents and place them randomly
agents = MoneyAgent.create_agents(
self,
self.num_agents,
# Randomly select cells for each agent
self.random.choices(self.grid.all_cells.cells, k=self.num_agents)
)
# Add cells to the grid to test the grid
for i in range(width):
self.grid.add_cell(self.grid.cell_klass((i, i), random=self.random))
def step(self) -> None:
"""
Advance the model by one step:
1. Have agents move randomly
2. Have agents give money to others in their cell
"""
self.agents.shuffle_do("move")
self.agents.do("give_money")
def print_grid_state(model: MoneyModel) -> None:
"""
Print a simple text representation of the grid.
Args:
model: The model to display
"""
print("\nGrid State (number of agents in each cell):")
print("-" * (model.grid.width * 4 + 3))
num_agents = 0
for y in range(model.grid.height-1, -1, -1):
print("|", end=" ")
for x in range(model.grid.width):
cell = model.grid[x, y]
print(f"{len(cell.agents):2d}", end=" ")
num_agents += len(cell.agents)
print("|")
print("-" * (model.grid.width * 4 + 3))
print(f"Total number of agents: {num_agents}")
def main():
"""Run a demonstration of the money model."""
# Create model with 20 agents on a 5x5 grid
model = MoneyModel(n_agents=20, width=5, height=5, seed=42)
# Run for 10 steps
for step in range(100):
print(f"\nStep {step}")
print_grid_state(model)
# Print wealth stats
wealth_dist = [agent.wealth for agent in model.agents]
print("\nWealth Distribution:")
print(f"Min: {min(wealth_dist)}, Max: {max(wealth_dist)}, "
f"Average: {sum(wealth_dist)/len(wealth_dist):.2f}")
# Step the model
model.step()
if __name__ == "__main__":
main()
Metadata
Metadata
Assignees
Labels
bugRelease notes labelRelease notes label