blob: f2ae6183c95401dab4d8e40adee5e90181cf4004 [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -07002Copyright 2016 Open Networking Foundation ( ONF )
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07003
4Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
5the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
6or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070011 ( at your option ) any later version.
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070012
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with TestON. If not, see <http://www.gnu.org/licenses/>.
20"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -070021"""
You Wangdb927a52016-02-26 11:03:28 -080022Graph algorithm implementations for CHOTestMonkey
23Author: you@onlab.us
24"""
25class GraphHelper:
Jon Hall2bb3e212017-05-24 17:07:25 -070026
You Wangdb927a52016-02-26 11:03:28 -080027 """
28 This class implements graph algorithms for CHOTestMonkey.
29 It reads main.devices and main.links as vertices and edges.
Jon Hall2bb3e212017-05-24 17:07:25 -070030 Currently it offers functions for finding ( non- )cut-edges and vertices,
You Wangdb927a52016-02-26 11:03:28 -080031 which is realized based on chain-decomposition algorithm
32 """
33 def __init__( self ):
34 # Depth-first index of each node
35 self.DFI = []
36 # Parent vertex and egde of each node in depth-first search tree
37 self.parentDeviceInDFS = []
38 self.parentLinkInDFS = []
39 # Data structures for chain-decomposition algorithm
40 self.backEdges = {}
41 self.chains = []
42 self.currentDFI = 0
43 self.upDevices = []
44 for device in main.devices:
45 if device.isUp():
46 self.upDevices.append( device )
47 for i in range( len( main.devices ) ):
48 self.DFI.append( -1 )
49 self.parentDeviceInDFS.append( None )
50 self.parentLinkInDFS.append( None )
51
52 def genDFIandBackEdge( self, device ):
53 """
54 This function runs a depth-first search and get DFI of each node
55 as well as collect the back edges
56 """
57 self.DFI[ device.index ] = self.currentDFI
58 self.currentDFI += 1
59 for link in device.outgoingLinks:
60 if not link.isUp():
61 continue
62 backwardLink = link.backwardLink
63 neighbor = link.deviceB
64 if neighbor == self.parentDeviceInDFS[ device.index ]:
65 continue
66 elif self.DFI[ neighbor.index ] == -1:
67 self.parentDeviceInDFS[ neighbor.index ] = device
68 self.parentLinkInDFS[ neighbor.index ] = backwardLink
69 self.genDFIandBackEdge( neighbor )
70 else:
71 key = self.DFI[ neighbor.index ]
72 if key in self.backEdges.keys():
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070073 if link not in self.backEdges[ key ] and\
74 backwardLink not in self.backEdges[ key ]:
You Wangdb927a52016-02-26 11:03:28 -080075 self.backEdges[ key ].append( backwardLink )
76 else:
77 tempKey = self.DFI[ device.index ]
78 if tempKey in self.backEdges.keys():
Jeremy Ronquillo23fb2162017-09-15 14:59:57 -070079 if link not in self.backEdges[ tempKey ] and\
80 backwardLink not in self.backEdges[ tempKey ]:
You Wangdb927a52016-02-26 11:03:28 -080081 self.backEdges[ key ] = [ backwardLink ]
82 else:
83 self.backEdges[ key ] = [ backwardLink ]
84
85 def findChains( self ):
86 """
87 This function finds all the 'chains' for chain-decomposition algorithm
88 """
Jon Hall2bb3e212017-05-24 17:07:25 -070089 keyList = sorted( self.backEdges.keys() )
You Wangdb927a52016-02-26 11:03:28 -080090 deviceIsVisited = []
91 for i in range( len( main.devices ) ):
92 deviceIsVisited.append( 0 )
93 for key in keyList:
94 backEdgeList = self.backEdges[ key ]
95 for link in backEdgeList:
96 chain = []
97 currentLink = link
98 sourceDevice = link.deviceA
99 while True:
100 currentDevice = currentLink.deviceA
101 nextDevice = currentLink.deviceB
102 deviceIsVisited[ currentDevice.index ] = 1
103 chain.append( currentLink )
104 if nextDevice == sourceDevice or deviceIsVisited[ nextDevice.index ] == 1:
105 break
106 currentLink = self.parentLinkInDFS[ nextDevice.index ]
107 self.chains.append( chain )
108
109 def getNonCutEdges( self ):
110 """
111 This function returns all non-cut-edges of a graph
112 """
113 assert len( self.upDevices ) != 0
114 self.genDFIandBackEdge( self.upDevices[ 0 ] )
115 self.findChains()
116 nonCutEdges = []
117 for chain in self.chains:
118 for link in chain:
119 nonCutEdges.append( link )
120 return nonCutEdges
121
122 def getNonCutVertices( self ):
123 """
124 This function returns all non-cut-vertices of a graph
125 """
126 nonCutEdges = self.getNonCutEdges()
127 nonCutVertices = []
128 for device in self.upDevices:
129 deviceIsNonCut = True
130 for link in device.outgoingLinks:
131 if link.isUp() and not ( link in nonCutEdges or link.backwardLink in nonCutEdges ):
132 deviceIsNonCut = False
133 break
134 if deviceIsNonCut:
135 nonCutVertices.append( device )
136 return nonCutVertices
137
138 def printDFI( self ):
139 print self.DFI
140
141 def printParentInDFS( self ):
142 print self.parentInDFS
143
144 def printBackEdges( self ):
145 print self.backEdges
146
147 def printChains( self ):
148 chainIndex = 0
149 for chain in self.chains:
150 print chainIndex
151 for link in chain:
152 print link
153 chainIndex += 1