Add modify hooks

I am currently writing some algorithms on top of python-igraph. Some of these algorithms store data on vertices/edges. However, if an edge/vertex is added/removed, those calculations will not be valid any longer. Therefore, I would like to propose an on_modify() hook that is called after any of the graph-modifying (Graph.add_vertex, Graph.add_edges, Vertex.delete, …) methods. I could use them to (re-)set some flags indicating whether some of the algorithms have produced output that is still valid.

Another alternative I thought of was to add a simple ImmutableGraph wrapper around Graph disabling all the graph modifying functions.

If there already is a way to achieve this, I would be happy if someone could point me in the right direction.

If this is considered useful, I could implement it myself, as it seems like only the python code needs to be changed.

If you are thinking about subclassing Graph into an ImmutableGraph, you could also subclass it in a way that you add the hook function and make add_vertex(), add_edges() and all the other functions call this hook function. It might not catch all cases where a graph can get modified; the C core of igraph can easily call igraph_add_vertices() and other functions on a low-level graph directly, without going through the Python layer, but this is probably rare enough that you don’t need to care about it too much if you would like to implement it only for your own purposes. However, for a long-term solution that eventually gets merged into python-igraph, I think it is inevitable to add this functionality directly to the C core of the library because that’s the part where all the modifications to the graph must eventually go through.

In fact, there is already a mechanism similar to the one proposed here in the C core library; it is called the attribute handler interface. Its purpose is to allow higher-level interfaces implement their own attribute storage mechanism and to get notified about changes in the underlying graph structure so they can adjust the attributes; for instance, if some vertices are deleted, the Python attribute handler gets called via its permute_vertices() method (in C) and this is how the Python interfaces gets to know that the attributes corresponding to the deleted vertices should be removed from the attribute storage.

I believe that in the end the optimal solution would be either:

  • to allow the user to extend the basic Python attribute handler in Python, either globally or on a per-graph basis (but then this would be limited to the Python interface only), or
  • to re-purpose the attribute handler table in the C layer as some kind of “event handler interface”; the attribute handler table would then be just one kind of event handler that is interested in changes happening to graph objects, and allow the user to register additional event handlers on graphs, either globally or on a per-graph basis. The advantage would be that higher-level interfaces would benefit from this as well, not only the Python interface.

@szhorvat What do you think? We have also talked about caching certain graph properties inside the igraph_t graph object (e.g., whether the graph is simple, whether the graph is a DAG etc). This caching mechanism could also be implemented in terms of a generic event handler where the graph property cach gets invalidated if certain events happen to the graph.