Reputation: 127
I have a python dictionary that is representing a graph. I wish to identify the root/independent nodes so that I can process them simultaneously and then the next nodes will become root/independent nodes. I am confused about how to implement this technique in python.
Below is a sample dictionary:
my_graph = {
1:[4],
2:[6],
3:[9],
4:[5,7],
5:[8],
6:[],
7:[],
8:[],
9:[]
}
I will divide the process into different frames. The expected result depending upon the above dictionary is given as:
1- start: root/independent nodes are = 1,2,3
2- after frame 1 root/independent nodes are = 4,6,9
3- after frame 2 root/independent nodes are = 5,7
4- after frame 3 root/independent nodes are = 8
Edit 1: I am trying to get sequence in any form e.g. a list, array or any other similar data-structure to a dependency graph of nodes in given dictionary, where each child node is dependent on its parent node so cannot be processed before parent. As a next step, I wish to get some parallelism i.e. I can process all root nodes at once.
I have been reading about Dask and luigui but not sure if they are the ultimate solution or I can do it some simple way.
Upvotes: 3
Views: 1978
Reputation: 1363
Much easier:
while d: #'d' is a dictionary
roots = set(d).difference(*d.values())
print(roots)
[d.pop(k) for k in roots]
or in a recursive way:
def traverse(d):
if d:
roots = set(d).difference(*d.values())
print(roots)
[d.pop(k) for k in roots]
return traverse(d)
Either way prints:
set([1, 2, 3])
set([4, 6, 9])
set([5, 7])
set([8])
Upvotes: 0
Reputation: 114481
This is called "topological sort". A simple algorithm is
You may get to a stop before completion if the graph is not a tree (there are loops). In this case you will get to a point where the graph is not empty but there is no available root.
In your case
def tsort(graph):
counts = dict((k, 0) for k in graph)
for n, neighbors in graph.items():
for nh in neighbors:
counts[nh] = counts[nh] + 1
while graph:
roots = [k for k in graph if counts[k] == 0]
if not roots:
raise RuntimeError("Cycles present, no topological sort possible")
print("roots", roots)
for r in roots:
print("Processing", r)
for nh in graph[r]:
counts[nh] -= 1
del graph[r]
Upvotes: 2
Reputation: 43830
Sounds like you want to perform a Topological Sort
You can use the library, toposort to do the heaving lifting for you, it will determine the dependencies and order in which the nodes should be processed:
import toposort
my_graph = {
1:[4],
2:[6],
3:[9],
4:[5,7],
5:[8],
6:[],
7:[],
8:[],
9:[]
}
# change values to sets (required by toposort)
for key, value in my_graph.items():
my_graph[key] = set(value)
result = toposort.toposort(my_graph)
print(list(result))
[{6, 7, 8, 9}, {2, 3, 5}, {4}, {1}]
Upvotes: 0