Skip to content

Dynamic Discrete Spaces #2754

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

Closed
quaquel opened this issue Apr 14, 2025 · 8 comments · Fixed by #2755
Closed

Dynamic Discrete Spaces #2754

quaquel opened this issue Apr 14, 2025 · 8 comments · Fixed by #2755
Labels
feature Release notes label

Comments

@quaquel
Copy link
Member

quaquel commented Apr 14, 2025

Currently, all DiscreteSpace subclasses rely on @cache and @cached_property for neighborhood-related functionality. This is critical for performance. However, if you want to represent a dynamically changing discrete space (e.g., a dynamic network), this is currently not possible.

It seems that functools offers a clear_cache function that can be called on anything decorated with a caching decorator. This means that it is possible to retain the performance benefits of caching while also being able to clear it on specific parts of the DiscreteSpace.

Something like the following is roughly what would be needed. Note that this is not tested and just quickly put together based on some docs.

class DynamicNetwork(Network):
	
	def add_cell(cell:Cell):
		self.G.add_node(cell.coordinate)
		self._cells[cell.coordinate] = cell.coordinate

	def add_edge(cell1:Cell, cell2:Cell):
		self.G.add_edge(cell1.coordinate, cell2.coordinate)

		for cell in [cell1, cell2]:
			cell.get_neighborhood.cache_clear()
			cell.neigbhoorhood.cache_clear()
			cell._neighborhood.cache_clear()
			self._connect_single_cell(cell)

	def remove_cell(cell:Cell):
		neigbors = cell.neighborhood

		self.G.remove_node(cell.coordinate)
		
		# iterate over all neighbors
		for cell in neighbors:
			cell.get_neighborhood.cache_clear()
			cell.neigbhoorhood.cache_clear()
			cell._neighborhood.cache_clear()
			self._connect_single_cell(cell)


	def remove_edge(cell1:Cell, cell2:Cell):
		self.G.remove_edge(cell1.coordinate, cell2.coordinate)

		for cell in [cell1, cell2]:
			cell.get_neighborhood.cache_clear()
			cell.neigbhoorhood.cache_clear()
			cell._neighborhood.cache_clear()
			self._connect_single_cell(cell)
@Sahil-Chhoker
Copy link
Collaborator

Can I ask how does caching prevent the dynamic nature of these spaces?

@quaquel
Copy link
Member Author

quaquel commented Apr 14, 2025

The neighborhood of a given cell is cached. If you next change the neigborhood by either removing or adding a cell to it, you have invalidated the cache.

@Sahil-Chhoker
Copy link
Collaborator

Does the cache not update with the new neighborhood?

@quaquel
Copy link
Member Author

quaquel commented Apr 14, 2025

no caching takes whatever was the return of the first ever time the function was called.

@Sahil-Chhoker
Copy link
Collaborator

Would it be beneficial in any way that we build our own caching function that automatically updates according to the necessary neighbor or is it too time consuming (performance wise)?

@quaquel
Copy link
Member Author

quaquel commented Apr 14, 2025

Why implement something ourselves that is well covered by an existing library? Also, how would any cache know it needs to be updated? The cache_clear function is provided explicitly to cover our use case.

Separately, thinking about the issue a bit more, my hunch is to implement the add_cell, remove_cell, add_edge and remove_edge (probably these need to be renamed to something a bit more generic) at the level of DiscreteSpace. In this way, all subclasses are automatically dynamic.

For example, a while ago someone wanted to add walls to a space. With a remove_edge method this becomes trivial to do.

@Sahil-Chhoker
Copy link
Collaborator

Thanks for this discussion, I think I kind of get it now!

@quaquel
Copy link
Member Author

quaquel commented Apr 14, 2025

I opened a PR: #2755 so let's move further discussion to there.

@EwoutH EwoutH added the feature Release notes label label Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Release notes label
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants