Skip to content

add agents property to all spaces #2418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions mesa/experimental/cell_space/discrete_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from random import Random
from typing import Any, Generic, TypeVar

from mesa.agent import AgentSet
from mesa.experimental.cell_space.cell import Cell
from mesa.experimental.cell_space.cell_collection import CellCollection
from mesa.space import PropertyLayer
Expand Down Expand Up @@ -55,6 +56,11 @@ def __init__(
def cutoff_empties(self): # noqa
return 7.953 * len(self._cells) ** 0.384

@property
def agents(self) -> AgentSet:
"""Return an AgentSet with the agents in the space."""
return AgentSet(self.all_cells.agents, random=self.random)

def _connect_cells(self): ...
def _connect_single_cell(self, cell: T): ...

Expand Down
56 changes: 55 additions & 1 deletion mesa/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import numpy.typing as npt

# For Mypy
from .agent import Agent
from .agent import Agent, AgentSet

# for better performance, we calculate the tuple to use in the is_integer function
_types_integer = (int, np.integer)
Expand Down Expand Up @@ -164,6 +164,26 @@
@overload
def __getitem__(self, index: int | Sequence[Coordinate]) -> list[GridContent]: ...

@property
def agents(self) -> AgentSet:
"""Return an AgentSet with the agents in the space."""
agents = []
for entry in self:
if not entry:
continue
if not isinstance(entry, list):
entry = [entry] # noqa PLW2901
for agent in entry:
agents.append(agent)

# getting the rng is a bit hacky because old style spaces don't have the rng
try:
rng = agents[0].random
except IndexError:

Check warning on line 182 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L182

Added line #L182 was not covered by tests
# there are no agents in the space
rng = None

Check warning on line 184 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L184

Added line #L184 was not covered by tests
return AgentSet(agents, random=rng)

@overload
def __getitem__(
self, index: tuple[int | slice, int | slice]
Expand Down Expand Up @@ -1344,6 +1364,19 @@
self._index_to_agent: dict[int, Agent] = {}
self._agent_to_index: dict[Agent, int | None] = {}

@property
def agents(self) -> AgentSet:
"""Return an AgentSet with the agents in the space."""
agents = list(self._agent_to_index)

# getting the rng is a bit hacky because old style spaces don't have the rng
try:
rng = agents[0].random
except IndexError:

Check warning on line 1375 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L1375

Added line #L1375 was not covered by tests
# there are no agents in the space
rng = None

Check warning on line 1377 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L1377

Added line #L1377 was not covered by tests
return AgentSet(agents, random=rng)

def _build_agent_cache(self):
"""Cache agents positions to speed up neighbors calculations."""
self._index_to_agent = {}
Expand Down Expand Up @@ -1517,6 +1550,27 @@
for node_id in self.G.nodes:
g.nodes[node_id]["agent"] = self.default_val()

@property
def agents(self) -> AgentSet:
"""Return an AgentSet with the agents in the space."""
agents = []
for node_id in self.G.nodes:
entry = self.G.nodes[node_id]["agent"]
if not entry:
continue
if not isinstance(entry, list):
entry = [entry]

Check warning on line 1562 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L1562

Added line #L1562 was not covered by tests
for agent in entry:
agents.append(agent)

# getting the rng is a bit hacky because old style spaces don't have the rng
try:
rng = agents[0].random
except IndexError:

Check warning on line 1569 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L1569

Added line #L1569 was not covered by tests
# there are no agents in the space
rng = None

Check warning on line 1571 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L1571

Added line #L1571 was not covered by tests
return AgentSet(agents, random=rng)

@staticmethod
def default_val() -> list:
"""Default value for a new node."""
Expand Down
20 changes: 20 additions & 0 deletions tests/test_cell_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,29 @@ def test_empties_space():
for i in range(8):
grid._cells[i].add_agent(CellAgent(model))


def test_agents_property():
"""Test empties method for Discrete Spaces."""
import networkx as nx

n = 10
m = 20
seed = 42
G = nx.gnm_random_graph(n, m, seed=seed) # noqa: N806
grid = Network(G)

model = Model()
for i in range(8):
grid._cells[i].add_agent(CellAgent(model))

cell = grid.select_random_empty_cell()
assert cell.coordinate in {8, 9}

assert len(grid.agents) == 8

for i, j in enumerate(sorted(grid.agents.get("unique_id"))):
assert (i + 1) == j # unique_id starts from 1


def test_cell():
"""Test Cell class."""
Expand Down
21 changes: 21 additions & 0 deletions tests/test_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ def setUp(self):
self.agents.append(a)
self.space.place_agent(a, pos)

def test_agents_property(self):
"""Test whether space.agents returns correct agents."""
for i, agent in enumerate(self.space.agents):
self.assertEqual(i, agent.unique_id)

self.assertEqual(len(REMOVAL_TEST_AGENTS), len(self.space.agents))

def test_remove_first(self):
"""Test removing the first entry."""
agent_to_remove = self.agents[0]
Expand Down Expand Up @@ -403,6 +410,13 @@ def setUp(self): # noqa: D102
self.agents.append(a)
self.space.place_agent(a, pos)

def test_agents_property(self):
"""Test whether space.agents returns correct agents."""
for i, agent in enumerate(self.space.agents):
self.assertEqual(i, agent.unique_id)

self.assertEqual(len(TEST_AGENTS_GRID), len(self.space.agents))

def test_agent_positions(self):
"""Ensure that the agents are all placed properly."""
for i, pos in enumerate(TEST_AGENTS_GRID):
Expand Down Expand Up @@ -827,6 +841,13 @@ def setUp(self):
self.agents.append(a)
self.space.place_agent(a, pos)

def test_agents_property(self):
"""Test whether space.agents returns correct agents."""
for i, agent in enumerate(self.space.agents):
self.assertEqual(i, agent.unique_id)

self.assertEqual(len(TEST_AGENTS_NETWORK_SINGLE), len(self.space.agents))

def test_agent_positions(self):
"""Ensure that the agents are all placed properly."""
for i, pos in enumerate(TEST_AGENTS_NETWORK_SINGLE):
Expand Down
Loading