I have this kind of Directed Acyclic Graph with multiple roots:
And I need to get a list with nodes sorted by directions and grouped by steps, like this:
ordering = [
[1, 3],
[2],
[4],
[5, 6],
[7]
]
Maybe there is some ready algorithm for this? I tried networkx.algorithm
but all of them can return me only a flat list without grouping by steps.
Essentially, Kahn's algorithm works by keeping track of the number of incoming edges into each node (indegree). It repeatedly: Finds nodes with no incoming edge, that is, nodes with zero indegree (no dependency). Stores the nodes with zero indegree in a stack/queue and deletes them from the original graph.
A DiGraph stores nodes and edges with optional data, or attributes. DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. Nodes can be arbitrary (hashable) Python objects with optional key/value attributes.
In computer science, a topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering.
Create a new digraph G' with two vertices v and v' for each vertex v in G. For each edge v->w in G, include two edges: v->w' and w->v'. Now, any path from s to v' in G' corresponds to an odd-length path from s to v in G.
nx.topological_sort
almost does what you want; the only difference is that it doesn't group items that enter the queue at the same time, but it's straightforward to adapt the source to make it do so:
def topological_sort_grouped(G):
indegree_map = {v: d for v, d in G.in_degree() if d > 0}
zero_indegree = [v for v, d in G.in_degree() if d == 0]
while zero_indegree:
yield zero_indegree
new_zero_indegree = []
for v in zero_indegree:
for _, child in G.edges(v):
indegree_map[child] -= 1
if not indegree_map[child]:
new_zero_indegree.append(child)
zero_indegree = new_zero_indegree
With your example:
In [21]: list(nx.topological_sort(G))
Out[21]: [3, 1, 2, 4, 6, 7, 5]
In [22]: list(topological_sort_grouped(G))
Out[22]: [[1, 3], [2], [4], [5, 6], [7]]
In practice, I have to wonder if there's a situation where this construction is more useful than just using nx.topological_sort
(or nx.lexicographical_topological_sort
) directly?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With