blob: a61676ea388a469542b5f77429ff366f312a40eb [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
2Graph algorithm implementations for CHOTestMonkey
3Author: you@onlab.us
4"""
5class GraphHelper:
Jon Hall2bb3e212017-05-24 17:07:25 -07006
You Wangdb927a52016-02-26 11:03:28 -08007 """
8 This class implements graph algorithms for CHOTestMonkey.
9 It reads main.devices and main.links as vertices and edges.
Jon Hall2bb3e212017-05-24 17:07:25 -070010 Currently it offers functions for finding ( non- )cut-edges and vertices,
You Wangdb927a52016-02-26 11:03:28 -080011 which is realized based on chain-decomposition algorithm
12 """
13 def __init__( self ):
14 # Depth-first index of each node
15 self.DFI = []
16 # Parent vertex and egde of each node in depth-first search tree
17 self.parentDeviceInDFS = []
18 self.parentLinkInDFS = []
19 # Data structures for chain-decomposition algorithm
20 self.backEdges = {}
21 self.chains = []
22 self.currentDFI = 0
23 self.upDevices = []
24 for device in main.devices:
25 if device.isUp():
26 self.upDevices.append( device )
27 for i in range( len( main.devices ) ):
28 self.DFI.append( -1 )
29 self.parentDeviceInDFS.append( None )
30 self.parentLinkInDFS.append( None )
31
32 def genDFIandBackEdge( self, device ):
33 """
34 This function runs a depth-first search and get DFI of each node
35 as well as collect the back edges
36 """
37 self.DFI[ device.index ] = self.currentDFI
38 self.currentDFI += 1
39 for link in device.outgoingLinks:
40 if not link.isUp():
41 continue
42 backwardLink = link.backwardLink
43 neighbor = link.deviceB
44 if neighbor == self.parentDeviceInDFS[ device.index ]:
45 continue
46 elif self.DFI[ neighbor.index ] == -1:
47 self.parentDeviceInDFS[ neighbor.index ] = device
48 self.parentLinkInDFS[ neighbor.index ] = backwardLink
49 self.genDFIandBackEdge( neighbor )
50 else:
51 key = self.DFI[ neighbor.index ]
52 if key in self.backEdges.keys():
53 if not link in self.backEdges[ key ] and\
Jon Hall2bb3e212017-05-24 17:07:25 -070054 not backwardLink in self.backEdges[ key ]:
You Wangdb927a52016-02-26 11:03:28 -080055 self.backEdges[ key ].append( backwardLink )
56 else:
57 tempKey = self.DFI[ device.index ]
58 if tempKey in self.backEdges.keys():
59 if not link in self.backEdges[ tempKey ] and\
Jon Hall2bb3e212017-05-24 17:07:25 -070060 not backwardLink in self.backEdges[ tempKey ]:
You Wangdb927a52016-02-26 11:03:28 -080061 self.backEdges[ key ] = [ backwardLink ]
62 else:
63 self.backEdges[ key ] = [ backwardLink ]
64
65 def findChains( self ):
66 """
67 This function finds all the 'chains' for chain-decomposition algorithm
68 """
Jon Hall2bb3e212017-05-24 17:07:25 -070069 keyList = sorted( self.backEdges.keys() )
You Wangdb927a52016-02-26 11:03:28 -080070 deviceIsVisited = []
71 for i in range( len( main.devices ) ):
72 deviceIsVisited.append( 0 )
73 for key in keyList:
74 backEdgeList = self.backEdges[ key ]
75 for link in backEdgeList:
76 chain = []
77 currentLink = link
78 sourceDevice = link.deviceA
79 while True:
80 currentDevice = currentLink.deviceA
81 nextDevice = currentLink.deviceB
82 deviceIsVisited[ currentDevice.index ] = 1
83 chain.append( currentLink )
84 if nextDevice == sourceDevice or deviceIsVisited[ nextDevice.index ] == 1:
85 break
86 currentLink = self.parentLinkInDFS[ nextDevice.index ]
87 self.chains.append( chain )
88
89 def getNonCutEdges( self ):
90 """
91 This function returns all non-cut-edges of a graph
92 """
93 assert len( self.upDevices ) != 0
94 self.genDFIandBackEdge( self.upDevices[ 0 ] )
95 self.findChains()
96 nonCutEdges = []
97 for chain in self.chains:
98 for link in chain:
99 nonCutEdges.append( link )
100 return nonCutEdges
101
102 def getNonCutVertices( self ):
103 """
104 This function returns all non-cut-vertices of a graph
105 """
106 nonCutEdges = self.getNonCutEdges()
107 nonCutVertices = []
108 for device in self.upDevices:
109 deviceIsNonCut = True
110 for link in device.outgoingLinks:
111 if link.isUp() and not ( link in nonCutEdges or link.backwardLink in nonCutEdges ):
112 deviceIsNonCut = False
113 break
114 if deviceIsNonCut:
115 nonCutVertices.append( device )
116 return nonCutVertices
117
118 def printDFI( self ):
119 print self.DFI
120
121 def printParentInDFS( self ):
122 print self.parentInDFS
123
124 def printBackEdges( self ):
125 print self.backEdges
126
127 def printChains( self ):
128 chainIndex = 0
129 for chain in self.chains:
130 print chainIndex
131 for link in chain:
132 print link
133 chainIndex += 1