diff DepGraph.py @ 4:3a56cd936c59

Cleanup some code. Add code for breaking loops in the dependency tree.
author Tom Fredrik Blenning Klaussen <bfg@blenning.no>
date Mon, 24 Sep 2012 01:16:43 +0200
parents a1224150b8f6
children 8952a4f7aa95
line wrap: on
line diff
--- a/DepGraph.py	Sun Sep 16 21:31:41 2012 +0200
+++ b/DepGraph.py	Mon Sep 24 01:16:43 2012 +0200
@@ -1,3 +1,4 @@
+import copy, sys
 from types import *
 
 class DepGraph:
@@ -11,14 +12,9 @@
         self.values.append(value)
 
 
-    def addDependency(self, src, dst):
-        if not type(dst) is ListType:
-            dst = [ dst ]
-
+    def rightSize(self):
         vl = len(self.values)
         dl = len(self.deps)
-        si = self.values.index(src)
-        
 
         if dl != vl:
             full = []
@@ -32,30 +28,102 @@
 
             for i in range(0, dl):
                 self.deps[i].append(exp[:])
-                
+
+    def addDependency(self, src, dst):
+        if not type(dst) is ListType:
+            dst = [ dst ]
+
+        self.rightSize()                
+
+        si = self.values.index(src)
         for d in dst:
             if d in self.values:
                 di = self.values.index(d)
                 self.deps[si][di] = True
 
+    @staticmethod
+    def identifyStronglyConnectedComponents(deps):
+        index=0
+        S=[]
+        vindex={}
+        lowlink={}
+        retVal=[]
+        for v in range(len(deps)):
+            if not v in vindex:
+                retVal.extend(DepGraph.strongconnect(deps, v, index, vindex, lowlink, S))
+        return retVal
+
+    @staticmethod
+    def strongconnect(deps, v, index, vindex, lowlink, S):
+        retVal = []
+        # Set the depth index for v to the smallest unused index
+        vindex[v] = index
+        lowlink[v] = index
+        #print index
+        index += 1
+        S.append(v)
+
+        # Consider successors of v        
+        for w in range(len(deps)):
+            if not deps[w][v]:
+                continue
+            if not w in vindex:
+                # Successor w has not yet been visited; recurse on it
+                res = DepGraph.strongconnect(deps, w, index, vindex, lowlink, S)
+                retVal.extend(res)
+                lowlink[v] = min(lowlink[v], lowlink[w])
+            elif w in S:
+                # Successor w is in stack S and hence in the current SCC
+                lowlink[v] = min(lowlink[v], vindex[w])
+
+        # If v is a root node, pop the stack and generate an SCC
+        if lowlink[v] == vindex[v]:
+            #start a new strongly connected component
+            component = []
+            w = None
+            while w != v:
+                w = S.pop()
+                #add w to current strongly connected component
+                component.append(w)
+            retVal.append(component)
+        return retVal
+
+    @staticmethod
+    def dissolveStronglyConnectedComponents(deps):
+        dissolved = True
+        while dissolved:
+            dissolved = False
+            strong = DepGraph.identifyStronglyConnectedComponents(deps)
+            for s in strong:
+                if len(s) > 1:
+                    #We remove the first dependency, and see how it goes.
+                    v = s[0]
+                    for w in s[1:]:
+                        if deps[w][v]:
+                            #print "Remove link %d -> %d" % (w, v)
+                            deps[w][v] = False
+                            dissolved = True
+                            break
+        return deps
+        sys.exit(1)
 
     @staticmethod
     def directedGraphInternal(deps):
         dl = len(deps)
-        myVals = []
+        startPoints = []
         for i in range(dl):
             if not max(deps[i]):
-                myVals.append(i)
+                startPoints.append(i)
 
-        for i in myVals:
+        for i in startPoints:
             for j in range(dl):
                 deps[j][i] = False
 
-        retVal = myVals
+        retVal = startPoints
 
-        if len(deps) != len(myVals):
-            subVals = self.directedGraphInternal(deps)
-            for val in myVals:
+        if len(deps) != len(startPoints):
+            subVals = DepGraph.directedGraphInternal(deps)
+            for val in startPoints:
                 if val in subVals:
                     ind = subVals.index(val)
                     del subVals[ind]
@@ -80,8 +148,13 @@
             res += s
         return res
 
-    def directedGraph(self):
-        deps = self.deps[:][:]
+    def depGraphRepr(self):
+        return self.printableDepgraph(self.deps)
+
+    def directedGraph(self, force = True):
+        deps = copy.deepcopy(self.deps)
+        if force:
+            deps = self.dissolveStronglyConnectedComponents(deps)
         vals = self.directedGraphInternal(deps)
         retVal = []
         for i in vals: