-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
remove_edges_from causing RuntimeError on certain view generators #2717
Description
In certain cases when remove_edges_from is operating on an view generator it will fail with a RuntimeError due to the yielded objects being the same as those removed.
I have observed it in two cases:
-
On on view returned by nx.selfloop_edges operating on MultiGraph and MultiDiGraph objects.
G.remove_edges_from(nx.selfloop_edges(G))is a standard construction for removing self-loops. It works with Graph and DiGraph, but fails for MultiGraph and MultiDiGraph. -
On the view returned by nx.edges for all graph types. The construction
G.remove_edges_from(nx.edges(G))might not be very useful, but the error also occurs when using functions from itertools to manipulate the view of nx.edges(G). Examples below.
Of course, in 2 the behaviour might perhaps be expected - the view seems to be an iterator to the same object as being manipulated, which is problematic. (A workaround is of course to create a list from it.)
However in 1, the selfloop view seems to be handled for Graph and DiGraph, so might it not be expected to work also for the ones provided for MultiGraph and MultiDiGraph?
Error-producing example
These three examples all fail:
Removing self-loops from MultiGraph
import networkx as nx
G = nx.MultiGraph([(0,0), (1,1), (0,1)])
G.remove_edges_from(nx.selfloop_edges(G)) # Fail here
Error Message
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/networkx/classes/multigraph.py", line 603, in remove_edges_from
for e in ebunch:
File "/usr/lib/python3.6/site-packages/networkx/classes/function.py", line 1150, in <genexpr>
if n in nbrs for d in nbrs[n].values())
File "/usr/lib/python3.6/_collections_abc.py", line 761, in __iter__
for key in self._mapping:
RuntimeError: dictionary changed size during iteration
Removing all edges from Graph
import networkx as nx
G = nx.Graph([(0,1), (1,2), (2,3)])
G.remove_edges_from(nx.edges(G)) # Fail here
Error Message
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/networkx/classes/graph.py", line 1038, in remove_edges_from
for e in ebunch:
File "/usr/lib/python3.6/site-packages/networkx/classes/reportviews.py", line 1024, in __iter__
for nbr in nbrs:
RuntimeError: dictionary changed size during iteration
Manipulating edge view using itertools:
import networkx as nx
import itertools
G = nx.DiGraph([(0,1), (1,2), (2,3)])
# Remove edges not staring at 1.
e_iter = itertools.filterfalse(lambda e : e[0] == 1, nx.edges(G))
G.remove_edges_from(e_iter) # Fail here
Error Message
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/networkx/classes/digraph.py", line 753, in remove_edges_from
for e in ebunch:
File "/usr/lib/python3.6/site-packages/networkx/classes/reportviews.py", line 914, in __iter__
for nbr in nbrs:
RuntimeError: dictionary changed size during iteration
Version information
NetworkX: 2.0
sys.version_info(major=3, minor=6, micro=2, releaselevel='final', serial=0)
Finally, thanks for your work on NetworkX.