blob: 6d28f4aa19db758d5d9f640540f69b1469e564cc [file] [log] [blame]
Sapan Bhatia26d40bc2014-05-12 15:28:02 -04001#!/usr/bin/python
2
3import time
4import traceback
5import commands
6import threading
7import json
8import pdb
9
10from datetime import datetime
11from collections import defaultdict
12
Sapan Bhatiab1d8a0f2014-09-01 17:41:19 -040013# Assumes that there are no empty dependencies
14# in the graph. E.g. Foo -> []
15def dfs(graph, visit):
16 nodes = graph.keys()
17 edge_nodes = set()
18
19 for n in nodes:
20 edge_nodes|=set(graph[n])
21
22 print 'Edge nodes=',edge_nodes
23 print 'Nodes=',nodes
24
25 sinks = list(edge_nodes - set(nodes))
26 sources = list(set(nodes) - edge_nodes)
27
28 print 'Sinks =',sinks
29 print 'Sources =',sources
30
31 nodes.extend(sinks)
32
33 for s in sinks:
34 graph[s]=[]
35
36 visited = set(sources)
37 stack = sources
38 while stack:
39 current = stack.pop()
40 visit(current)
41 for node in graph[current]:
42 if node not in visited:
43 stack.append(node)
44 visited.add(node)
45
46
47# Topological sort + find connected components
48# Notes:
49# - Uses a stack instead of recursion
50# - Forfeits optimization involving tracking currently visited nodes
51
52def toposort_with_components(g, steps=None):
53 # Get set of all nodes, including those without outgoing edges
54 keys = set(g.keys())
55 values = set({})
56 for v in g.values():
57 values=values | set(v)
58
59 all_nodes=list(keys|values)
60 if (not steps):
61 steps = all_nodes
62
63 # Final order
64 order = {}
65
66 # Index of newest component
67 cidx = 0
68
69 # DFS stack, not using recursion
70 stack = []
71
72 # Unmarked set
73 unmarked = all_nodes
74
75 # visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
76
77 while unmarked:
78 stack.insert(0,unmarked[0]) # push first unmarked
79
80 while (stack):
81 n = stack[0]
82 add = True
83 try:
84 for m in g[n]:
85 if (m in unmarked):
86 if (m not in stack):
87 add = False
88 stack.insert(0,m)
89 else:
90 # Should not happen, if so there's a loop
91 print 'Loop at %s'%m
92 except KeyError:
93 pass
94 if (add):
95 if (n in steps):
96 order.append(n)
97 item = stack.pop(0)
98 unmarked.remove(item)
99
100 noorder = list(set(steps) - set(order))
101
102 # Steps that do not have an order get pushed as
103 # separate components that run in parallel.
104 for s in noorder:
105 order['%d'%cidx] = [s]
106 cidx+=1
107
108 return order + noorder
109
Sapan Bhatia26d40bc2014-05-12 15:28:02 -0400110# Topological sort
111# Notes:
112# - Uses a stack instead of recursion
113# - Forfeits optimization involving tracking currently visited nodes
114def toposort(g, steps=None):
115 # Get set of all nodes, including those without outgoing edges
116 keys = set(g.keys())
117 values = set({})
118 for v in g.values():
119 values=values | set(v)
120
121 all_nodes=list(keys|values)
122 if (not steps):
123 steps = all_nodes
124
125 # Final order
126 order = []
127
128 # DFS stack, not using recursion
129 stack = []
130
131 # Unmarked set
132 unmarked = all_nodes
133
134 # visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
135
136 while unmarked:
137 stack.insert(0,unmarked[0]) # push first unmarked
138
139 while (stack):
140 n = stack[0]
141 add = True
142 try:
143 for m in g[n]:
144 if (m in unmarked):
145 if (m not in stack):
146 add = False
147 stack.insert(0,m)
148 else:
149 # Should not happen, if so there's a loop
150 print 'Loop at %s'%m
151 except KeyError:
152 pass
153 if (add):
154 if (n in steps):
155 order.append(n)
156 item = stack.pop(0)
157 unmarked.remove(item)
158
159 noorder = list(set(steps) - set(order))
160 return order + noorder
161
162def main():
163 graph_file=open('planetstack.deps').read()
164 g = json.loads(graph_file)
165 print toposort(g)
166
167if (__name__=='__main__'):
168 main()
169
170#print toposort({'a':'b','b':'c','c':'d','d':'c'},['d','c','b','a'])