Mesa Space Module#

Objects used to add a spatial component to a model.

Grid: base grid, which creates a rectangular grid. SingleGrid: extension to Grid which strictly enforces one agent per cell. MultiGrid: extension to Grid where each cell can contain a set of agents. HexGrid: extension to Grid to handle hexagonal neighbors. ContinuousSpace: a two-dimensional space where each agent has an arbitrary

position of float’s.

NetworkGrid: a network where each node contains zero or more agents.

accept_tuple_argument(wrapped_function: F) F[source]#

Decorator to allow grid methods that take a list of (x, y) coord tuples to also handle a single position, by automatically wrapping tuple in single-item list rather than forcing user to do it.

is_single_argument_function(function)[source]#

Check if a function is a single argument function.

class PropertyLayer(name: str, width: int, height: int, default_value, dtype=<class 'numpy.float64'>)[source]#

A class representing a layer of properties in a two-dimensional grid. Each cell in the grid can store a value of a specified data type.

Attributes:

name (str): The name of the property layer. width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). data (numpy.ndarray): A NumPy array representing the grid data.

Methods:

set_cell(position, value): Sets the value of a single cell. set_cells(value, condition=None): Sets the values of multiple cells, optionally based on a condition. modify_cell(position, operation, value): Modifies the value of a single cell using an operation. modify_cells(operation, value, condition_function): Modifies the values of multiple cells using an operation. select_cells(condition, return_list): Selects cells that meet a specified condition. aggregate_property(operation): Performs an aggregate operation over all cells.

Initializes a new PropertyLayer instance.

Args:

name (str): The name of the property layer. width (int): The width of the grid (number of columns). Must be a positive integer. height (int): The height of the grid (number of rows). Must be a positive integer. default_value: The default value to initialize each cell in the grid. Should ideally

be of the same type as specified by the dtype parameter.

dtype (data-type, optional): The desired data-type for the grid’s elements. Default is np.float64.

Raises:

ValueError: If width or height is not a positive integer.

Notes:

A UserWarning is raised if the default_value is not of a type compatible with dtype. The dtype parameter can accept both Python data types (like bool, int or float) and NumPy data types (like np.int64 or np.float64). Using NumPy data types is recommended (except for bool) for better control over the precision and efficiency of data storage and computations, especially in cases of large data volumes or specialized numerical operations.

set_cell(position: tuple[int, int], value)[source]#

Update a single cell’s value in-place.

set_cells(value, condition=None)[source]#

Perform a batch update either on the entire grid or conditionally, in-place.

Args:

value: The value to be used for the update. condition: (Optional) A callable (like a lambda function or a NumPy ufunc)

that returns a boolean array when applied to the data.

modify_cell(position: tuple[int, int], operation, value=None)[source]#

Modify a single cell using an operation, which can be a lambda function or a NumPy ufunc. If a NumPy ufunc is used, an additional value should be provided.

Args:

position: The grid coordinates of the cell to modify. operation: A function to apply. Can be a lambda function or a NumPy ufunc. value: The value to be used if the operation is a NumPy ufunc. Ignored for lambda functions.

modify_cells(operation, value=None, condition_function=None)[source]#

Modify cells using an operation, which can be a lambda function or a NumPy ufunc. If a NumPy ufunc is used, an additional value should be provided.

Args:

operation: A function to apply. Can be a lambda function or a NumPy ufunc. value: The value to be used if the operation is a NumPy ufunc. Ignored for lambda functions. condition_function: (Optional) A callable that returns a boolean array when applied to the data.

select_cells(condition, return_list=True)[source]#

Find cells that meet a specified condition using NumPy’s boolean indexing, in-place.

Args:

condition: A callable that returns a boolean array when applied to the data. return_list: (Optional) If True, return a list of (x, y) tuples. Otherwise, return a boolean array.

Returns:

A list of (x, y) tuples or a boolean array.

aggregate_property(operation)[source]#

Perform an aggregate operation (e.g., sum, mean) on a property across all cells.

Args:

operation: A function to apply. Can be a lambda function or a NumPy ufunc.

class SingleGrid(width: int, height: int, torus: bool, property_layers: None | PropertyLayer | list[PropertyLayer] = None)[source]#

Rectangular grid where each cell contains exactly at most one agent.

Grid cells are indexed by [x, y], where [0, 0] is assumed to be the bottom-left and [width-1, height-1] is the top-right. If a grid is toroidal, the top and bottom, and left and right, edges wrap to each other.

This class provides a property empties that returns a set of coordinates for all empty cells in the grid. It is automatically updated whenever agents are added or removed from the grid. The empties property should be used for efficient access to current empty cells rather than manually iterating over the grid to check for emptiness.

Properties:

width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of (x, y) tuples for all empty cells. This set is

maintained internally and provides a performant way to query the grid for empty spaces.

Initializes a new _PropertyGrid instance with specified dimensions and optional property layers.

Args:

width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). torus (bool): A boolean indicating if the grid should behave like a torus. property_layers (None | PropertyLayer | list[PropertyLayer], optional): A single PropertyLayer instance,

a list of PropertyLayer instances, or None to initialize without any property layers.

Raises:

ValueError: If a property layer’s dimensions do not match the grid dimensions.

place_agent(agent: Agent, pos: tuple[int, int]) None[source]#

Place the agent at the specified location, and set its pos variable.

remove_agent(agent: Agent) None[source]#

Remove the agent from the grid and set its pos attribute to None.

add_property_layer(property_layer: PropertyLayer)#

Adds a new property layer to the grid.

Args:

property_layer (PropertyLayer): The PropertyLayer instance to be added to the grid.

Raises:

ValueError: If a property layer with the same name already exists in the grid. ValueError: If the dimensions of the property layer do not match the grid’s dimensions.

coord_iter() Iterator[tuple[Agent | None, tuple[int, int]]]#

An iterator that returns positions as well as cell contents.

static default_val() None#

Default value for new cell elements.

property empty_mask: ndarray#

Returns a boolean mask indicating empty cells on the grid.

exists_empty_cells() bool#

Return True if any cells empty else False.

get_neighborhood(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Sequence[tuple[int, int]]#

Return a list of cells that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals) If False, return Von Neumann neighborhood (exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of coordinate tuples representing the neighborhood; With radius 1, at most 9 if Moore, 5 if Von Neumann (8 and 4 if not including the center).

get_neighborhood_mask(pos: tuple[int, int], moore: bool, include_center: bool, radius: int) ndarray#

Generate a boolean mask representing the neighborhood. Helper method for select_cells_multi_properties() and move_agent_to_random_cell()

Args:

pos (Coordinate): Center of the neighborhood. moore (bool): True for Moore neighborhood, False for Von Neumann. include_center (bool): Include the central cell in the neighborhood. radius (int): The radius of the neighborhood.

Returns:

np.ndarray: A boolean mask representing the neighborhood.

get_neighbors(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) list[Agent]#

Return a list of neighbors to a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).

is_cell_empty(pos: tuple[int, int]) bool#

Returns a bool of the contents of a cell.

iter_neighborhood(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Iterator[tuple[int, int]]#

Return an iterator over cell coordinates that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).

iter_neighbors(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Iterator[Agent]#

Return an iterator over neighbors to a certain point.

Args:

pos: Coordinates for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).

move_agent(agent: Agent, pos: tuple[int, int]) None#

Move an agent from its current position to a new position.

Args:
agent: Agent object to move. Assumed to have its current location

stored in a ‘pos’ tuple.

pos: Tuple of new position to move the agent to.

move_agent_to_one_of(agent: Agent, pos: list[tuple[int, int]], selection: str = 'random', handle_empty: str | None = None) None#

Move an agent to one of the given positions.

Args:

agent: Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple. pos: List of possible positions. selection: String, either “random” (default) or “closest”. If “closest” is selected and multiple

cells are the same distance, one is chosen randomly.

handle_empty: String, either “warning”, “error” or None (default). If “warning” or “error” is selected

and no positions are given (an empty list), a warning or error is raised respectively.

move_to_empty(agent: Agent) None#

Moves agent to a random empty cell, vacating agent’s old cell.

out_of_bounds(pos: tuple[int, int]) bool#

Determines whether position is off the grid, returns the out of bounds coordinate.

remove_property_layer(property_name: str)#

Removes a property layer from the grid by its name.

Args:

property_name (str): The name of the property layer to be removed.

Raises:

ValueError: If a property layer with the given name does not exist in the grid.

select_cells(conditions: dict | None = None, extreme_values: dict | None = None, masks: ndarray | list[ndarray] = None, only_empty: bool = False, return_list: bool = True) list[tuple[int, int]] | ndarray#

Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.

Args:

conditions (dict): A dictionary where keys are property names and values are callables that return a boolean when applied. extreme_values (dict): A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’. masks (np.ndarray | list[np.ndarray], optional): A mask or list of masks to restrict the selection. only_empty (bool, optional): If True, only select cells that are empty. Default is False. return_list (bool, optional): If True, return a list of coordinates, otherwise return a mask.

Returns:

Union[list[Coordinate], np.ndarray]: Coordinates where conditions are satisfied or the combined mask.

swap_pos(agent_a: Agent, agent_b: Agent) None#

Swap agents positions

torus_adj(pos: tuple[int, int]) tuple[int, int]#

Convert coordinate, handling torus looping.

class MultiGrid(width: int, height: int, torus: bool, property_layers: None | PropertyLayer | list[PropertyLayer] = None)[source]#

Rectangular grid where each cell can contain more than one agent.

Grid cells are indexed by [x, y], where [0, 0] is assumed to be at bottom-left and [width-1, height-1] is the top-right. If a grid is toroidal, the top and bottom, and left and right, edges wrap to each other.

This class maintains an empties property, which is a set of coordinates for all cells that currently contain no agents. This property is updated automatically as agents are added to or removed from the grid.

Properties:

width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of (x, y) tuples for all empty cells.

Initializes a new _PropertyGrid instance with specified dimensions and optional property layers.

Args:

width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). torus (bool): A boolean indicating if the grid should behave like a torus. property_layers (None | PropertyLayer | list[PropertyLayer], optional): A single PropertyLayer instance,

a list of PropertyLayer instances, or None to initialize without any property layers.

Raises:

ValueError: If a property layer’s dimensions do not match the grid dimensions.

static default_val() list[Agent][source]#

Default value for new cell elements.

place_agent(agent: Agent, pos: tuple[int, int]) None[source]#

Place the agent at the specified location, and set its pos variable.

remove_agent(agent: Agent) None[source]#

Remove the agent from the given location and set its pos attribute to None.

iter_neighbors(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Iterator[Agent][source]#

Return an iterator over neighbors to a certain point.

Args:

pos: Coordinates for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).

add_property_layer(property_layer: PropertyLayer)#

Adds a new property layer to the grid.

Args:

property_layer (PropertyLayer): The PropertyLayer instance to be added to the grid.

Raises:

ValueError: If a property layer with the same name already exists in the grid. ValueError: If the dimensions of the property layer do not match the grid’s dimensions.

coord_iter() Iterator[tuple[Agent | None, tuple[int, int]]]#

An iterator that returns positions as well as cell contents.

property empty_mask: ndarray#

Returns a boolean mask indicating empty cells on the grid.

exists_empty_cells() bool#

Return True if any cells empty else False.

get_neighborhood(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Sequence[tuple[int, int]]#

Return a list of cells that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals) If False, return Von Neumann neighborhood (exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of coordinate tuples representing the neighborhood; With radius 1, at most 9 if Moore, 5 if Von Neumann (8 and 4 if not including the center).

get_neighborhood_mask(pos: tuple[int, int], moore: bool, include_center: bool, radius: int) ndarray#

Generate a boolean mask representing the neighborhood. Helper method for select_cells_multi_properties() and move_agent_to_random_cell()

Args:

pos (Coordinate): Center of the neighborhood. moore (bool): True for Moore neighborhood, False for Von Neumann. include_center (bool): Include the central cell in the neighborhood. radius (int): The radius of the neighborhood.

Returns:

np.ndarray: A boolean mask representing the neighborhood.

get_neighbors(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) list[Agent]#

Return a list of neighbors to a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of non-None objects in the given neighborhood; at most 9 if Moore, 5 if Von-Neumann (8 and 4 if not including the center).

is_cell_empty(pos: tuple[int, int]) bool#

Returns a bool of the contents of a cell.

iter_neighborhood(pos: tuple[int, int], moore: bool, include_center: bool = False, radius: int = 1) Iterator[tuple[int, int]]#

Return an iterator over cell coordinates that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. moore: If True, return Moore neighborhood

(including diagonals)

If False, return Von Neumann neighborhood

(exclude diagonals)

include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).

move_agent(agent: Agent, pos: tuple[int, int]) None#

Move an agent from its current position to a new position.

Args:
agent: Agent object to move. Assumed to have its current location

stored in a ‘pos’ tuple.

pos: Tuple of new position to move the agent to.

move_agent_to_one_of(agent: Agent, pos: list[tuple[int, int]], selection: str = 'random', handle_empty: str | None = None) None#

Move an agent to one of the given positions.

Args:

agent: Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple. pos: List of possible positions. selection: String, either “random” (default) or “closest”. If “closest” is selected and multiple

cells are the same distance, one is chosen randomly.

handle_empty: String, either “warning”, “error” or None (default). If “warning” or “error” is selected

and no positions are given (an empty list), a warning or error is raised respectively.

move_to_empty(agent: Agent) None#

Moves agent to a random empty cell, vacating agent’s old cell.

out_of_bounds(pos: tuple[int, int]) bool#

Determines whether position is off the grid, returns the out of bounds coordinate.

remove_property_layer(property_name: str)#

Removes a property layer from the grid by its name.

Args:

property_name (str): The name of the property layer to be removed.

Raises:

ValueError: If a property layer with the given name does not exist in the grid.

select_cells(conditions: dict | None = None, extreme_values: dict | None = None, masks: ndarray | list[ndarray] = None, only_empty: bool = False, return_list: bool = True) list[tuple[int, int]] | ndarray#

Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.

Args:

conditions (dict): A dictionary where keys are property names and values are callables that return a boolean when applied. extreme_values (dict): A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’. masks (np.ndarray | list[np.ndarray], optional): A mask or list of masks to restrict the selection. only_empty (bool, optional): If True, only select cells that are empty. Default is False. return_list (bool, optional): If True, return a list of coordinates, otherwise return a mask.

Returns:

Union[list[Coordinate], np.ndarray]: Coordinates where conditions are satisfied or the combined mask.

swap_pos(agent_a: Agent, agent_b: Agent) None#

Swap agents positions

torus_adj(pos: tuple[int, int]) tuple[int, int]#

Convert coordinate, handling torus looping.

class HexSingleGrid(width: int, height: int, torus: bool, property_layers: None | PropertyLayer | list[PropertyLayer] = None)[source]#

Hexagonal SingleGrid: a SingleGrid where neighbors are computed according to a hexagonal tiling of the grid.

Functions according to odd-q rules. See http://www.redblobgames.com/grids/hexagons/#coordinates for more.

This class also maintains an empties property, similar to SingleGrid, which provides a set of coordinates for all empty hexagonal cells.

Properties:

width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of hexagonal coordinates for all empty cells.

Initializes a new _PropertyGrid instance with specified dimensions and optional property layers.

Args:

width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). torus (bool): A boolean indicating if the grid should behave like a torus. property_layers (None | PropertyLayer | list[PropertyLayer], optional): A single PropertyLayer instance,

a list of PropertyLayer instances, or None to initialize without any property layers.

Raises:

ValueError: If a property layer’s dimensions do not match the grid dimensions.

add_property_layer(property_layer: PropertyLayer)#

Adds a new property layer to the grid.

Args:

property_layer (PropertyLayer): The PropertyLayer instance to be added to the grid.

Raises:

ValueError: If a property layer with the same name already exists in the grid. ValueError: If the dimensions of the property layer do not match the grid’s dimensions.

coord_iter() Iterator[tuple[Agent | None, tuple[int, int]]]#

An iterator that returns positions as well as cell contents.

static default_val() None#

Default value for new cell elements.

property empty_mask: ndarray#

Returns a boolean mask indicating empty cells on the grid.

exists_empty_cells() bool#

Return True if any cells empty else False.

get_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[tuple[int, int]]#

Return a list of coordinates that are in the neighborhood of a certain point. To calculate the neighborhood for a HexGrid the parity of the x coordinate of the point is important, the neighborhood can be sketched as:

Always: (0,-), (0,+) When x is even: (-,+), (-,0), (+,+), (+,0) When x is odd: (-,0), (-,-), (+,0), (+,-)

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).

get_neighborhood_mask(pos: tuple[int, int], moore: bool, include_center: bool, radius: int) ndarray#

Generate a boolean mask representing the neighborhood. Helper method for select_cells_multi_properties() and move_agent_to_random_cell()

Args:

pos (Coordinate): Center of the neighborhood. moore (bool): True for Moore neighborhood, False for Von Neumann. include_center (bool): Include the central cell in the neighborhood. radius (int): The radius of the neighborhood.

Returns:

np.ndarray: A boolean mask representing the neighborhood.

get_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[Agent]#

Return a list of neighbors to a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of non-None objects in the given neighborhood

is_cell_empty(pos: tuple[int, int]) bool#

Returns a bool of the contents of a cell.

iter_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[tuple[int, int]]#

Return an iterator over cell coordinates that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of coordinate tuples representing the neighborhood.

iter_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[Agent]#

Return an iterator over neighbors to a certain point.

Args:

pos: Coordinates for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of non-None objects in the given neighborhood

move_agent(agent: Agent, pos: tuple[int, int]) None#

Move an agent from its current position to a new position.

Args:
agent: Agent object to move. Assumed to have its current location

stored in a ‘pos’ tuple.

pos: Tuple of new position to move the agent to.

move_agent_to_one_of(agent: Agent, pos: list[tuple[int, int]], selection: str = 'random', handle_empty: str | None = None) None#

Move an agent to one of the given positions.

Args:

agent: Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple. pos: List of possible positions. selection: String, either “random” (default) or “closest”. If “closest” is selected and multiple

cells are the same distance, one is chosen randomly.

handle_empty: String, either “warning”, “error” or None (default). If “warning” or “error” is selected

and no positions are given (an empty list), a warning or error is raised respectively.

move_to_empty(agent: Agent) None#

Moves agent to a random empty cell, vacating agent’s old cell.

out_of_bounds(pos: tuple[int, int]) bool#

Determines whether position is off the grid, returns the out of bounds coordinate.

place_agent(agent: Agent, pos: tuple[int, int]) None#

Place the agent at the specified location, and set its pos variable.

remove_agent(agent: Agent) None#

Remove the agent from the grid and set its pos attribute to None.

remove_property_layer(property_name: str)#

Removes a property layer from the grid by its name.

Args:

property_name (str): The name of the property layer to be removed.

Raises:

ValueError: If a property layer with the given name does not exist in the grid.

select_cells(conditions: dict | None = None, extreme_values: dict | None = None, masks: ndarray | list[ndarray] = None, only_empty: bool = False, return_list: bool = True) list[tuple[int, int]] | ndarray#

Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.

Args:

conditions (dict): A dictionary where keys are property names and values are callables that return a boolean when applied. extreme_values (dict): A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’. masks (np.ndarray | list[np.ndarray], optional): A mask or list of masks to restrict the selection. only_empty (bool, optional): If True, only select cells that are empty. Default is False. return_list (bool, optional): If True, return a list of coordinates, otherwise return a mask.

Returns:

Union[list[Coordinate], np.ndarray]: Coordinates where conditions are satisfied or the combined mask.

swap_pos(agent_a: Agent, agent_b: Agent) None#

Swap agents positions

torus_adj(pos: tuple[int, int]) tuple[int, int]#

Convert coordinate, handling torus looping.

class HexMultiGrid(width: int, height: int, torus: bool, property_layers: None | PropertyLayer | list[PropertyLayer] = None)[source]#

Hexagonal MultiGrid: a MultiGrid where neighbors are computed according to a hexagonal tiling of the grid.

Functions according to odd-q rules. See http://www.redblobgames.com/grids/hexagons/#coordinates for more.

Similar to the standard MultiGrid, this class maintains an empties property, which is a set of coordinates for all hexagonal cells that currently contain no agents. This property is updated automatically as agents are added to or removed from the grid.

Properties:

width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus. empties: Returns a set of hexagonal coordinates for all empty cells.

Initializes a new _PropertyGrid instance with specified dimensions and optional property layers.

Args:

width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). torus (bool): A boolean indicating if the grid should behave like a torus. property_layers (None | PropertyLayer | list[PropertyLayer], optional): A single PropertyLayer instance,

a list of PropertyLayer instances, or None to initialize without any property layers.

Raises:

ValueError: If a property layer’s dimensions do not match the grid dimensions.

add_property_layer(property_layer: PropertyLayer)#

Adds a new property layer to the grid.

Args:

property_layer (PropertyLayer): The PropertyLayer instance to be added to the grid.

Raises:

ValueError: If a property layer with the same name already exists in the grid. ValueError: If the dimensions of the property layer do not match the grid’s dimensions.

coord_iter() Iterator[tuple[Agent | None, tuple[int, int]]]#

An iterator that returns positions as well as cell contents.

static default_val() list[Agent]#

Default value for new cell elements.

property empty_mask: ndarray#

Returns a boolean mask indicating empty cells on the grid.

exists_empty_cells() bool#

Return True if any cells empty else False.

get_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[tuple[int, int]]#

Return a list of coordinates that are in the neighborhood of a certain point. To calculate the neighborhood for a HexGrid the parity of the x coordinate of the point is important, the neighborhood can be sketched as:

Always: (0,-), (0,+) When x is even: (-,+), (-,0), (+,+), (+,0) When x is odd: (-,0), (-,-), (+,0), (+,-)

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).

get_neighborhood_mask(pos: tuple[int, int], moore: bool, include_center: bool, radius: int) ndarray#

Generate a boolean mask representing the neighborhood. Helper method for select_cells_multi_properties() and move_agent_to_random_cell()

Args:

pos (Coordinate): Center of the neighborhood. moore (bool): True for Moore neighborhood, False for Von Neumann. include_center (bool): Include the central cell in the neighborhood. radius (int): The radius of the neighborhood.

Returns:

np.ndarray: A boolean mask representing the neighborhood.

get_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[Agent]#

Return a list of neighbors to a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of non-None objects in the given neighborhood

is_cell_empty(pos: tuple[int, int]) bool#

Returns a bool of the contents of a cell.

iter_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[tuple[int, int]]#

Return an iterator over cell coordinates that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of coordinate tuples representing the neighborhood.

iter_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[Agent]#

Return an iterator over neighbors to a certain point.

Args:

pos: Coordinates for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of non-None objects in the given neighborhood

move_agent(agent: Agent, pos: tuple[int, int]) None#

Move an agent from its current position to a new position.

Args:
agent: Agent object to move. Assumed to have its current location

stored in a ‘pos’ tuple.

pos: Tuple of new position to move the agent to.

move_agent_to_one_of(agent: Agent, pos: list[tuple[int, int]], selection: str = 'random', handle_empty: str | None = None) None#

Move an agent to one of the given positions.

Args:

agent: Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple. pos: List of possible positions. selection: String, either “random” (default) or “closest”. If “closest” is selected and multiple

cells are the same distance, one is chosen randomly.

handle_empty: String, either “warning”, “error” or None (default). If “warning” or “error” is selected

and no positions are given (an empty list), a warning or error is raised respectively.

move_to_empty(agent: Agent) None#

Moves agent to a random empty cell, vacating agent’s old cell.

out_of_bounds(pos: tuple[int, int]) bool#

Determines whether position is off the grid, returns the out of bounds coordinate.

place_agent(agent: Agent, pos: tuple[int, int]) None#

Place the agent at the specified location, and set its pos variable.

remove_agent(agent: Agent) None#

Remove the agent from the given location and set its pos attribute to None.

remove_property_layer(property_name: str)#

Removes a property layer from the grid by its name.

Args:

property_name (str): The name of the property layer to be removed.

Raises:

ValueError: If a property layer with the given name does not exist in the grid.

select_cells(conditions: dict | None = None, extreme_values: dict | None = None, masks: ndarray | list[ndarray] = None, only_empty: bool = False, return_list: bool = True) list[tuple[int, int]] | ndarray#

Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.

Args:

conditions (dict): A dictionary where keys are property names and values are callables that return a boolean when applied. extreme_values (dict): A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’. masks (np.ndarray | list[np.ndarray], optional): A mask or list of masks to restrict the selection. only_empty (bool, optional): If True, only select cells that are empty. Default is False. return_list (bool, optional): If True, return a list of coordinates, otherwise return a mask.

Returns:

Union[list[Coordinate], np.ndarray]: Coordinates where conditions are satisfied or the combined mask.

swap_pos(agent_a: Agent, agent_b: Agent) None#

Swap agents positions

torus_adj(pos: tuple[int, int]) tuple[int, int]#

Convert coordinate, handling torus looping.

class HexGrid(width: int, height: int, torus: bool)[source]#

Hexagonal Grid: a Grid where neighbors are computed according to a hexagonal tiling of the grid.

Functions according to odd-q rules. See http://www.redblobgames.com/grids/hexagons/#coordinates for more.

Properties:

width, height: The grid’s width and height. torus: Boolean which determines whether to treat the grid as a torus.

Initializes a new _PropertyGrid instance with specified dimensions and optional property layers.

Args:

width (int): The width of the grid (number of columns). height (int): The height of the grid (number of rows). torus (bool): A boolean indicating if the grid should behave like a torus. property_layers (None | PropertyLayer | list[PropertyLayer], optional): A single PropertyLayer instance,

a list of PropertyLayer instances, or None to initialize without any property layers.

Raises:

ValueError: If a property layer’s dimensions do not match the grid dimensions.

add_property_layer(property_layer: PropertyLayer)#

Adds a new property layer to the grid.

Args:

property_layer (PropertyLayer): The PropertyLayer instance to be added to the grid.

Raises:

ValueError: If a property layer with the same name already exists in the grid. ValueError: If the dimensions of the property layer do not match the grid’s dimensions.

coord_iter() Iterator[tuple[Agent | None, tuple[int, int]]]#

An iterator that returns positions as well as cell contents.

static default_val() None#

Default value for new cell elements.

property empty_mask: ndarray#

Returns a boolean mask indicating empty cells on the grid.

exists_empty_cells() bool#

Return True if any cells empty else False.

get_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[tuple[int, int]]#

Return a list of coordinates that are in the neighborhood of a certain point. To calculate the neighborhood for a HexGrid the parity of the x coordinate of the point is important, the neighborhood can be sketched as:

Always: (0,-), (0,+) When x is even: (-,+), (-,0), (+,+), (+,0) When x is odd: (-,0), (-,-), (+,0), (+,-)

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of coordinate tuples representing the neighborhood. For example with radius 1, it will return list with number of elements equals at most 9 (8) if Moore, 5 (4) if Von Neumann (if not including the center).

get_neighborhood_mask(pos: tuple[int, int], moore: bool, include_center: bool, radius: int) ndarray#

Generate a boolean mask representing the neighborhood. Helper method for select_cells_multi_properties() and move_agent_to_random_cell()

Args:

pos (Coordinate): Center of the neighborhood. moore (bool): True for Moore neighborhood, False for Von Neumann. include_center (bool): Include the central cell in the neighborhood. radius (int): The radius of the neighborhood.

Returns:

np.ndarray: A boolean mask representing the neighborhood.

get_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) list[Agent]#

Return a list of neighbors to a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

A list of non-None objects in the given neighborhood

is_cell_empty(pos: tuple[int, int]) bool#

Returns a bool of the contents of a cell.

iter_neighborhood(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[tuple[int, int]]#

Return an iterator over cell coordinates that are in the neighborhood of a certain point.

Args:

pos: Coordinate tuple for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of coordinate tuples representing the neighborhood.

iter_neighbors(pos: tuple[int, int], include_center: bool = False, radius: int = 1) Iterator[Agent]#

Return an iterator over neighbors to a certain point.

Args:

pos: Coordinates for the neighborhood to get. include_center: If True, return the (x, y) cell as well.

Otherwise, return surrounding cells only.

radius: radius, in cells, of neighborhood to get.

Returns:

An iterator of non-None objects in the given neighborhood

move_agent(agent: Agent, pos: tuple[int, int]) None#

Move an agent from its current position to a new position.

Args:
agent: Agent object to move. Assumed to have its current location

stored in a ‘pos’ tuple.

pos: Tuple of new position to move the agent to.

move_agent_to_one_of(agent: Agent, pos: list[tuple[int, int]], selection: str = 'random', handle_empty: str | None = None) None#

Move an agent to one of the given positions.

Args:

agent: Agent object to move. Assumed to have its current location stored in a ‘pos’ tuple. pos: List of possible positions. selection: String, either “random” (default) or “closest”. If “closest” is selected and multiple

cells are the same distance, one is chosen randomly.

handle_empty: String, either “warning”, “error” or None (default). If “warning” or “error” is selected

and no positions are given (an empty list), a warning or error is raised respectively.

move_to_empty(agent: Agent) None#

Moves agent to a random empty cell, vacating agent’s old cell.

out_of_bounds(pos: tuple[int, int]) bool#

Determines whether position is off the grid, returns the out of bounds coordinate.

place_agent(agent: Agent, pos: tuple[int, int]) None#

Place the agent at the specified location, and set its pos variable.

remove_agent(agent: Agent) None#

Remove the agent from the grid and set its pos attribute to None.

remove_property_layer(property_name: str)#

Removes a property layer from the grid by its name.

Args:

property_name (str): The name of the property layer to be removed.

Raises:

ValueError: If a property layer with the given name does not exist in the grid.

select_cells(conditions: dict | None = None, extreme_values: dict | None = None, masks: ndarray | list[ndarray] = None, only_empty: bool = False, return_list: bool = True) list[tuple[int, int]] | ndarray#

Select cells based on property conditions, extreme values, and/or masks, with an option to only select empty cells.

Args:

conditions (dict): A dictionary where keys are property names and values are callables that return a boolean when applied. extreme_values (dict): A dictionary where keys are property names and values are either ‘highest’ or ‘lowest’. masks (np.ndarray | list[np.ndarray], optional): A mask or list of masks to restrict the selection. only_empty (bool, optional): If True, only select cells that are empty. Default is False. return_list (bool, optional): If True, return a list of coordinates, otherwise return a mask.

Returns:

Union[list[Coordinate], np.ndarray]: Coordinates where conditions are satisfied or the combined mask.

swap_pos(agent_a: Agent, agent_b: Agent) None#

Swap agents positions

torus_adj(pos: tuple[int, int]) tuple[int, int]#

Convert coordinate, handling torus looping.

class ContinuousSpace(x_max: float, y_max: float, torus: bool, x_min: float = 0, y_min: float = 0)[source]#

Continuous space where each agent can have an arbitrary position.

Assumes that all agents have a pos property storing their position as an (x, y) tuple.

This class uses a numpy array internally to store agents in order to speed up neighborhood lookups. This array is calculated on the first neighborhood lookup, and is updated if agents are added or removed.

The concept of ‘empty cells’ is not directly applicable in continuous space, as positions are not discretized.

Create a new continuous space.

Args:

x_max, y_max: Maximum x and y coordinates for the space. torus: Boolean for whether the edges loop around. x_min, y_min: (default 0) If provided, set the minimum x and y

coordinates for the space. Below them, values loop to the other edge (if torus=True) or raise an exception.

place_agent(agent: Agent, pos: tuple[float, float] | ndarray[Any, dtype[float]]) None[source]#

Place a new agent in the space.

Args:

agent: Agent object to place. pos: Coordinate tuple for where to place the agent.

move_agent(agent: Agent, pos: tuple[float, float] | ndarray[Any, dtype[float]]) None[source]#

Move an agent from its current position to a new position.

Args:

agent: The agent object to move. pos: Coordinate tuple to move the agent to.

remove_agent(agent: Agent) None[source]#

Remove an agent from the space.

Args:

agent: The agent object to remove

get_neighbors(pos: tuple[float, float] | ndarray[Any, dtype[float]], radius: float, include_center: bool = True) list[Agent][source]#

Get all agents within a certain radius.

Args:

pos: (x,y) coordinate tuple to center the search at. radius: Get all the objects within this distance of the center. include_center: If True, include an object at the exact provided

coordinates. i.e. if you are searching for the neighbors of a given agent, True will include that agent in the results.

get_heading(pos_1: tuple[float, float] | ndarray[Any, dtype[float]], pos_2: tuple[float, float] | ndarray[Any, dtype[float]]) tuple[float, float] | ndarray[Any, dtype[float]][source]#

Get the heading vector between two points, accounting for toroidal space. It is possible to calculate the heading angle by applying the atan2 function to the result.

Args:

pos_1, pos_2: Coordinate tuples for both points.

get_distance(pos_1: tuple[float, float] | ndarray[Any, dtype[float]], pos_2: tuple[float, float] | ndarray[Any, dtype[float]]) float[source]#

Get the distance between two point, accounting for toroidal space.

Args:

pos_1, pos_2: Coordinate tuples for both points.

torus_adj(pos: tuple[float, float] | ndarray[Any, dtype[float]]) tuple[float, float] | ndarray[Any, dtype[float]][source]#

Adjust coordinates to handle torus looping.

If the coordinate is out-of-bounds and the space is toroidal, return the corresponding point within the space. If the space is not toroidal, raise an exception.

Args:

pos: Coordinate tuple to convert.

out_of_bounds(pos: tuple[float, float] | ndarray[Any, dtype[float]]) bool[source]#

Check if a point is out of bounds.

class NetworkGrid(g: Any)[source]#

Network Grid where each node contains zero or more agents.

Create a new network.

Args:

G: a NetworkX graph instance.

static default_val() list[source]#

Default value for a new node.

place_agent(agent: Agent, node_id: int) None[source]#

Place an agent in a node.

get_neighborhood(node_id: int, include_center: bool = False, radius: int = 1) list[int][source]#

Get all adjacent nodes within a certain radius

get_neighbors(node_id: int, include_center: bool = False, radius: int = 1) list[Agent][source]#

Get all agents in adjacent nodes (within a certain radius).

move_agent(agent: Agent, node_id: int) None[source]#

Move an agent from its current node to a new node.

remove_agent(agent: Agent) None[source]#

Remove the agent from the network and set its pos attribute to None.

is_cell_empty(node_id: int) bool[source]#

Returns a bool of the contents of a cell.

get_cell_list_contents(cell_list: list[int]) list[Agent][source]#

Returns a list of the agents contained in the nodes identified in cell_list; nodes with empty content are excluded.

get_all_cell_contents() list[Agent][source]#

Returns a list of all the agents in the network.

iter_cell_list_contents(cell_list: list[int]) Iterator[Agent][source]#

Returns an iterator of the agents contained in the nodes identified in cell_list; nodes with empty content are excluded.