-
Notifications
You must be signed in to change notification settings - Fork 865
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
Make cell connections public and named #2296
Changes from 7 commits
6dd3081
82ddc05
2a9f3b4
05790e1
5bf9471
64bb4f7
bb4e9df
884f0f8
ed421e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,8 +9,11 @@ | |
from mesa.experimental.cell_space.cell_collection import CellCollection | ||
|
||
if TYPE_CHECKING: | ||
from mesa.agent import Agent | ||
from mesa.experimental.cell_space.cell_agent import CellAgent | ||
|
||
Coordinate = tuple[int, ...] | ||
|
||
|
||
class Cell: | ||
"""The cell represents a position in a discrete space. | ||
|
@@ -26,7 +29,7 @@ class Cell: | |
|
||
__slots__ = [ | ||
"coordinate", | ||
"_connections", | ||
"connections", | ||
"agents", | ||
"capacity", | ||
"properties", | ||
|
@@ -44,7 +47,7 @@ class Cell: | |
|
||
def __init__( | ||
self, | ||
coordinate: tuple[int, ...], | ||
coordinate: Coordinate, | ||
capacity: float | None = None, | ||
random: Random | None = None, | ||
) -> None: | ||
|
@@ -58,20 +61,24 @@ def __init__( | |
""" | ||
super().__init__() | ||
self.coordinate = coordinate | ||
self._connections: list[Cell] = [] # TODO: change to CellCollection? | ||
self.agents = [] # TODO:: change to AgentSet or weakrefs? (neither is very performant, ) | ||
self.connections: dict[Coordinate, Cell] = {} | ||
self.agents: list[ | ||
Agent | ||
] = [] # TODO:: change to AgentSet or weakrefs? (neither is very performant, ) | ||
self.capacity = capacity | ||
self.properties: dict[str, object] = {} | ||
self.properties: dict[Coordinate, object] = {} | ||
self.random = random | ||
|
||
def connect(self, other: Cell) -> None: | ||
def connect(self, other: Cell, name: Coordinate | None = None) -> None: | ||
"""Connects this cell to another cell. | ||
|
||
Args: | ||
other (Cell): other cell to connect to | ||
|
||
""" | ||
self._connections.append(other) | ||
if name is None: | ||
name = other.coordinate | ||
self.connections[name] = other | ||
|
||
def disconnect(self, other: Cell) -> None: | ||
"""Disconnects this cell from another cell. | ||
|
@@ -80,7 +87,9 @@ def disconnect(self, other: Cell) -> None: | |
other (Cell): other cell to remove from connections | ||
|
||
""" | ||
self._connections.remove(other) | ||
keys_to_remove = [k for k, v in self.connections.items() if v == other] | ||
for key in keys_to_remove: | ||
del self.connections[key] | ||
quaquel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def add_agent(self, agent: CellAgent) -> None: | ||
"""Adds an agent to the cell. | ||
|
@@ -123,30 +132,34 @@ def __repr__(self): # noqa | |
|
||
# FIXME: Revisit caching strategy on methods | ||
@cache # noqa: B019 | ||
def neighborhood(self, radius=1, include_center=False): | ||
def neighborhood(self, radius: int = 1, include_center: bool = False): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would it be possible to add a docstring. Also, and not perse necessary for this PR, but the name of this method has been tripping me up. The name suggests that it is an attribute, so perhaps at some point we should change this to something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed, there is some revisiting to be done here. I think at one point the idea was that this basically is an attribute/property for the default case, which is just a CellCollection of the the connections. Maybe we could actually have something like def get_neighborhood(self, radius: int = 1, include_center: bool = False):
...
@property
def neighborhood(self):
return self.get_neighborhood() So for the "normal" neighborhood you could do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this makes good sense. The most common case is indeed getting the direct neighborhood and it would be good if that is just a property. Naming-wise, what about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes more distinctive names sounds good. I'll have to think about |
||
"""Returns a list of all neighboring cells.""" | ||
return CellCollection( | ||
return CellCollection[Cell]( | ||
self._neighborhood(radius=radius, include_center=include_center), | ||
random=self.random, | ||
) | ||
|
||
# FIXME: Revisit caching strategy on methods | ||
@cache # noqa: B019 | ||
def _neighborhood(self, radius=1, include_center=False): | ||
def _neighborhood( | ||
self, radius: int = 1, include_center: bool = False | ||
) -> dict[Cell, list[Agent]]: | ||
# if radius == 0: | ||
# return {self: self.agents} | ||
if radius < 1: | ||
raise ValueError("radius must be larger than one") | ||
if radius == 1: | ||
neighborhood = {neighbor: neighbor.agents for neighbor in self._connections} | ||
neighborhood = { | ||
neighbor: neighbor.agents for neighbor in self.connections.values() | ||
} | ||
if not include_center: | ||
return neighborhood | ||
else: | ||
neighborhood[self] = self.agents | ||
return neighborhood | ||
else: | ||
neighborhood = {} | ||
for neighbor in self._connections: | ||
neighborhood: dict[Cell, list[Agent]] = {} | ||
for neighbor in self.connections.values(): | ||
neighborhood.update( | ||
neighbor._neighborhood(radius - 1, include_center=True) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please complete the docstring. Name is not defined as one of the arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, because I rebased the PR and not merged main into it, my precommit hooks did not fire locally, so I didn't catch this. Next time I am going to merge again.
Also note that this is indeed an error and happily catched by our CI :) pre-commit.ci