I have a working way of deleting all vertices of degree less than 2 in a graph until no more can be found.
But my solution has a significant issue which is that it calls Graph.delete_vertices()
for each iteration. This call is very slow on igraph Graphs because igraph is quick on queries but slow on updates because of indexing.
This means that doing this on a big graph (millions of nodes/edges) which I need takes a will, especially if there are a lot of chained degree 2 nodes ending in a degree 1 node.
import igraph as ig
graph = ig.Graph.Formula('D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G, H-F:G, H-I-J, Z-A, Y-B')
layout = graph.layout("kamada_kawai")
ig.plot(graph, layout=layout, bbox=(0, 0, 400, 400))
# Code needing of help
while vertices := [v for v in graph.vs.select(_degree_le=1)]:
graph.delete_vertices(vertices)
ig.plot(graph, layout=layout, bbox=(0, 0, 400, 400))
Start graph: (updated)
End graph: (updated)
In this example here, four graph updates are needed. The first pass deletes six nodes, the second deletes the three nodes that becomes degree 1 after the first update; then two nodes and a single node on the last update.
Edit: Alright I have a better way of doing it that doesn't require multiple graph updates. Not sure if it is the best way but it definitely makes more sense and is faster.
vertices = {v for v in graph.vs.select(_degree_le=1)}
needs_to_be_checked = set(vertices)
while needs_to_be_checked:
vertex = needs_to_be_checked.pop()
for n_vertex in vertex.neighbors():
if n_vertex in vertices:
continue
if n_vertex.degree() == 2:
vertices.add(n_vertex)
needs_to_be_checked.add(n_vertex)
graph.delete_vertices(vertices)
EDIT 2 (taking in consideration @DeathIncarnate's comment):
vertices = {v for v in graph.vs.select(_degree_le=1)}
needs_to_be_checked = set(vertices)
while needs_to_be_checked:
vertex = needs_to_be_checked.pop()
for n_vertex in vertex.neighbors():
if n_vertex in vertices \
or sum(1 for v in n_vertex.neighbors() if v not in vertices) > 1:
continue
vertices.add(n_vertex)
needs_to_be_checked.add(n_vertex)
graph.delete_vertices(vertices)
degree
won't have decreased yet, so your check needs to count [pseudocode]degree - count(neigbours in vertices)
or forcibly decrease thedegree
of neighbours of removed vertices as it goes. \$\endgroup\$