Skip to content

Commit

Permalink
_PropertyGrid: Implement multi-property cell selection and enhanced a…
Browse files Browse the repository at this point in the history
…gent movement

This commit introduces three significant enhancements for grids based on the _PropertyGrid in the mesa.space module:
1. `select_cells_multi_properties`: Allows for the selection of cells based on multiple property conditions, using a combination of NumPy operations. This method returns a list of coordinates satisfying the specified conditions.
2. `move_agent_to_random_cell`: Enables moving an agent to a random cell that meets specified property conditions, enhancing the flexibility in agent movements.
3. `move_agent_to_extreme_value_cell`: Facilitates moving an agent to a cell with the highest, lowest, or closest property value, based on a specified mode. This method extends agent movement capabilities, allowing for more dynamic and condition-based relocations.
  • Loading branch information
EwoutH committed Dec 4, 2023
1 parent b47d1b0 commit 784fdd7
Showing 1 changed file with 67 additions and 4 deletions.
71 changes: 67 additions & 4 deletions mesa/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,10 +647,73 @@ def remove_property_layer(self, property_name: str):
raise ValueError(f"Property layer {property_name} does not exist.")
del self.properties[property_name]

Check warning on line 648 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L647-L648

Added lines #L647 - L648 were not covered by tests

# TODO:
# - Select cells conditionally based on multiple properties
# - Move random cells conditionally based on multiple properties
# - Move to cell with highest/lowest/closest property value
def select_cells_multi_properties(self, conditions: dict) -> List[Coordinate]:
"""
Select cells based on multiple property conditions using NumPy.
Args:
conditions (dict): A dictionary where keys are property names and values are
callables that take a single argument (the property value)
and return a boolean.
Returns:
List[Coordinate]: A list of coordinates where the conditions are satisfied.
"""
# Start with a mask of all True values
combined_mask = np.ones((self.width, self.height), dtype=bool)

Check warning on line 663 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L663

Added line #L663 was not covered by tests

for prop_name, condition in conditions.items():
prop_layer = self.properties[prop_name].data

Check warning on line 666 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L666

Added line #L666 was not covered by tests
# Apply the condition to the property layer
prop_mask = condition(prop_layer)

Check warning on line 668 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L668

Added line #L668 was not covered by tests
# Combine with the existing mask using logical AND
combined_mask = np.logical_and(combined_mask, prop_mask)

Check warning on line 670 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L670

Added line #L670 was not covered by tests

# Extract coordinates from the combined mask
selected_cells = list(zip(*np.where(combined_mask)))
return selected_cells

Check warning on line 674 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L673-L674

Added lines #L673 - L674 were not covered by tests

def move_agent_to_random_cell(self, agent: Agent, conditions: dict) -> None:
"""
Move an agent to a random cell that meets specified property conditions.
If no eligible cells are found, issue a warning and keep the agent in its current position.
Args:
agent (Agent): The agent to move.
conditions (dict): Conditions for selecting the cell.
"""
eligible_cells = self.select_cells_multi_properties(conditions)

Check warning on line 685 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L685

Added line #L685 was not covered by tests
if not eligible_cells:
warn(f"No eligible cells found. Agent {agent.unique_id} remains in the current position.", RuntimeWarning)
return # Agent stays in the current position

Check warning on line 688 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L687-L688

Added lines #L687 - L688 were not covered by tests

# Randomly choose one of the eligible cells and move the agent
new_pos = agent.random.choice(eligible_cells)
self.move_agent(agent, new_pos)

Check warning on line 692 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L691-L692

Added lines #L691 - L692 were not covered by tests

def move_agent_to_extreme_value_cell(self, agent: Agent, property_name: str, mode: str) -> None:
"""
Move an agent to a cell with the highest, lowest, or closest property value.
Args:
agent (Agent): The agent to move.
property_name (str): The name of the property layer.
mode (str): 'highest', 'lowest', or 'closest'.
"""
prop_values = self.properties[property_name].data

Check warning on line 703 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L703

Added line #L703 was not covered by tests
if mode == 'highest':
target_value = np.max(prop_values)

Check warning on line 705 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L705

Added line #L705 was not covered by tests
elif mode == 'lowest':
target_value = np.min(prop_values)

Check warning on line 707 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L707

Added line #L707 was not covered by tests
elif mode == 'closest':
agent_value = prop_values[agent.pos]
target_value = prop_values[np.abs(prop_values - agent_value).argmin()]

Check warning on line 710 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L709-L710

Added lines #L709 - L710 were not covered by tests
else:
raise ValueError(f"Invalid mode {mode}. Choose from 'highest', 'lowest', or 'closest'.")

Check warning on line 712 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L712

Added line #L712 was not covered by tests

target_cells = list(zip(*np.where(prop_values == target_value)))
new_pos = agent.random.choice(target_cells)
self.move_agent(agent, new_pos)

Check warning on line 716 in mesa/space.py

View check run for this annotation

Codecov / codecov/patch

mesa/space.py#L714-L716

Added lines #L714 - L716 were not covered by tests


class SingleGrid(_PropertyGrid):
Expand Down

0 comments on commit 784fdd7

Please sign in to comment.