blob: 8ae1ff0d0628f44387e6be0cff5834f9bd3b01ef [file] [log] [blame]
You Wangdb927a52016-02-26 11:03:28 -08001"""
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07002Copyright 2016 Open Networking Foundation (ONF)
3
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
11 (at your option) any later version.
12
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"""
21
22"""
You Wangdb927a52016-02-26 11:03:28 -080023Graph algorithm implementations for CHOTestMonkey
24Author: you@onlab.us
25"""
26class GraphHelper:
Jon Hall2bb3e212017-05-24 17:07:25 -070027
You Wangdb927a52016-02-26 11:03:28 -080028 """
29 This class implements graph algorithms for CHOTestMonkey.
30 It reads main.devices and main.links as vertices and edges.
Jon Hall2bb3e212017-05-24 17:07:25 -070031 Currently it offers functions for finding ( non- )cut-edges and vertices,
You Wangdb927a52016-02-26 11:03:28 -080032 which is realized based on chain-decomposition algorithm
33 """
34 def __init__( self ):
35 # Depth-first index of each node
36 self.DFI = []
37 # Parent vertex and egde of each node in depth-first search tree
38 self.parentDeviceInDFS = []
39 self.parentLinkInDFS = []
40 # Data structures for chain-decomposition algorithm
41 self.backEdges = {}
42 self.chains = []
43 self.currentDFI = 0
44 self.upDevices = []
45 for device in main.devices:
46 if device.isUp():
47 self.upDevices.append( device )
48 for i in range( len( main.devices ) ):
49 self.DFI.append( -1 )
50 self.parentDeviceInDFS.append( None )
51 self.parentLinkInDFS.append( None )
52
53 def genDFIandBackEdge( self, device ):
54 """
55 This function runs a depth-first search and get DFI of each node
56 as well as collect the back edges
57 """
58 self.DFI[ device.index ] = self.currentDFI
59 self.currentDFI += 1
60 for link in device.outgoingLinks:
61 if not link.isUp():
62 continue
63 backwardLink = link.backwardLink
64 neighbor = link.deviceB
65 if neighbor == self.parentDeviceInDFS[ device.index ]:
66 continue
67 elif self.DFI[ neighbor.index ] == -1:
68 self.parentDeviceInDFS[ neighbor.index ] = device
69 self.parentLinkInDFS[ neighbor.index ] = backwardLink
70 self.genDFIandBackEdge( neighbor )
71 else:
72 key = self.DFI[ neighbor.index ]
73 if key in self.backEdges.keys():
74 if not link in self.backEdges[ key ] and\
Jon Hall2bb3e212017-05-24 17:07:25 -070075 not backwardLink in self.backEdges[ key ]:
You Wangdb927a52016-02-26 11:03:28 -080076 self.backEdges[ key ].append( backwardLink )
77 else:
78 tempKey = self.DFI[ device.index ]
79 if tempKey in self.backEdges.keys():
80 if not link in self.backEdges[ tempKey ] and\
Jon Hall2bb3e212017-05-24 17:07:25 -070081 not backwardLink in self.backEdges[ tempKey ]:
You Wangdb927a52016-02-26 11:03:28 -080082 self.backEdges[ key ] = [ backwardLink ]
83 else:
84 self.backEdges[ key ] = [ backwardLink ]
85
86 def findChains( self ):
87 """
88 This function finds all the 'chains' for chain-decomposition algorithm
89 """
Jon Hall2bb3e212017-05-24 17:07:25 -070090 keyList = sorted( self.backEdges.keys() )
You Wangdb927a52016-02-26 11:03:28 -080091 deviceIsVisited = []
92 for i in range( len( main.devices ) ):
93 deviceIsVisited.append( 0 )
94 for key in keyList:
95 backEdgeList = self.backEdges[ key ]
96 for link in backEdgeList:
97 chain = []
98 currentLink = link
99 sourceDevice = link.deviceA
100 while True:
101 currentDevice = currentLink.deviceA
102 nextDevice = currentLink.deviceB
103 deviceIsVisited[ currentDevice.index ] = 1
104 chain.append( currentLink )
105 if nextDevice == sourceDevice or deviceIsVisited[ nextDevice.index ] == 1:
106 break
107 currentLink = self.parentLinkInDFS[ nextDevice.index ]
108 self.chains.append( chain )
109
110 def getNonCutEdges( self ):
111 """
112 This function returns all non-cut-edges of a graph
113 """
114 assert len( self.upDevices ) != 0
115 self.genDFIandBackEdge( self.upDevices[ 0 ] )
116 self.findChains()
117 nonCutEdges = []
118 for chain in self.chains:
119 for link in chain:
120 nonCutEdges.append( link )
121 return nonCutEdges
122
123 def getNonCutVertices( self ):
124 """
125 This function returns all non-cut-vertices of a graph
126 """
127 nonCutEdges = self.getNonCutEdges()
128 nonCutVertices = []
129 for device in self.upDevices:
130 deviceIsNonCut = True
131 for link in device.outgoingLinks:
132 if link.isUp() and not ( link in nonCutEdges or link.backwardLink in nonCutEdges ):
133 deviceIsNonCut = False
134 break
135 if deviceIsNonCut:
136 nonCutVertices.append( device )
137 return nonCutVertices
138
139 def printDFI( self ):
140 print self.DFI
141
142 def printParentInDFS( self ):
143 print self.parentInDFS
144
145 def printBackEdges( self ):
146 print self.backEdges
147
148 def printChains( self ):
149 chainIndex = 0
150 for chain in self.chains:
151 print chainIndex
152 for link in chain:
153 print link
154 chainIndex += 1