11import queue
2+ import copy
23
34
45class DirectedGraph (object ):
@@ -136,7 +137,7 @@ def topological_sort(self):
136137 order = []
137138 statuses = {}
138139
139- assert (not self .contains_cycle ())
140+ assert (not self .contains_cycle ())
140141
141142 for vertex in self .get_vertex ():
142143 to_visit = [vertex ]
@@ -160,8 +161,15 @@ def topological_sort(self):
160161
161162 return order
162163
164+ def strongly_connected_components (self ):
165+ """
166+ Compute the vertices in the strongly connected components
167+ :return:
168+ """
169+ pass
163170
164- def main ():
171+
172+ def get_test_graph_1 ():
165173 dg = DirectedGraph ()
166174 dg .add_edge (0 , 1 )
167175 dg .add_edge (0 , 5 )
@@ -173,31 +181,22 @@ def main():
173181 dg .add_edge (6 , 5 )
174182 dg .add_edge (7 , 5 )
175183 dg .add_edge (7 , 5 )
176- # dg.add_edge(8, 0) # uncomment to create a cycle
177-
178- components , dfs_parents = dg .dfs ()
179-
180- print ("Components: " , components )
181- print ("Parents (dfs): " , dfs_parents )
182-
183- bfs_parents = dg .bfs ()
184- print ("Parents (bfs): " , bfs_parents )
185184
186- print ( "Contains a cycle: " , dg . contains_cycle ())
185+ return dg
187186
188- print ("Topological sort" , dg .topological_sort ())
189187
190- # another with edges added out of order
188+ def get_test_graph_2 ():
191189 dg_small = DirectedGraph ()
192190 dg_small .add_edge (2 , 1 )
193191 dg_small .add_edge (4 , 5 )
194192 dg_small .add_edge (0 , 1 )
195193 dg_small .add_edge (1 , 4 )
196194 dg_small .add_edge (1 , 3 )
197195
198- print ( "Topological sort" , dg_small . topological_sort ())
196+ return dg_small
199197
200- # making edges out of order with random~ish vertex numbers
198+
199+ def get_test_graph_3 ():
201200 dg_other = DirectedGraph ()
202201 dg_other .add_edge (3 , 11 )
203202 dg_other .add_edge (5 , 2 )
@@ -207,8 +206,74 @@ def main():
207206 dg_other .add_edge (4 , 7 )
208207 dg_other .add_edge (7 , 8 )
209208
210- print ("Topological sort" , dg_other .topological_sort ())
209+ return dg_other
210+
211+
212+ def get_test_graph_4 ():
213+ """
214+ Returns graph containing a cycle
215+ :return:
216+ """
217+ dg = copy .copy (get_test_graph_1 ())
218+ dg .add_edge (8 , 0 ) # creates cycle
219+
220+ return dg
221+
222+
223+ def get_test_graph_5 ():
224+ """
225+ Returns a graph with 3 cycles and 5 strongly connected components
226+ :return:
227+ """
228+ dg = DirectedGraph ()
229+ dg .add_edge (0 , 2 )
230+ dg .add_edge (1 , 3 )
231+ dg .add_edge (3 , 2 )
232+ dg .add_edge (2 , 1 )
233+ dg .add_edge (4 , 5 )
234+ dg .add_edge (5 , 6 )
235+ dg .add_edge (6 , 4 )
236+ dg .add_edge (3 , 5 )
237+ dg .add_edge (7 , 5 )
238+ dg .add_edge (8 , 10 )
239+ dg .add_edge (10 , 11 )
240+ dg .add_edge (11 , 9 )
241+ dg .add_edge (9 , 8 )
242+
243+
244+ def test_dfs ():
245+ dg1 = get_test_graph_1 ()
246+ c1 , p1 = dg1 .dfs ()
247+ assert (c1 == {0 , 3 , 7 })
248+ assert (p1 == {1 : 0 , 2 : 1 , 4 : 2 , 5 : 0 , 6 : 2 , 8 : 5 })
249+
250+
251+ def test_bfs ():
252+ dg1 = get_test_graph_1 ()
253+ p1 = dg1 .bfs ()
254+ assert (p1 == {1 : 0 , 2 : 1 , 4 : 2 , 5 : 0 , 6 : 2 , 8 : 5 })
255+
256+
257+ def test_contains_cycle ():
258+ assert (get_test_graph_1 ().contains_cycle () == False )
259+ assert (get_test_graph_2 ().contains_cycle () == False )
260+ assert (get_test_graph_3 ().contains_cycle () == False )
261+ assert (get_test_graph_4 ().contains_cycle () == True )
262+
263+
264+ def test_topological_sort ():
265+ assert (get_test_graph_1 ().topological_sort () == [7 , 3 , 0 , 1 , 2 , 4 , 6 , 5 , 8 ])
266+ assert (get_test_graph_2 ().topological_sort () == [2 , 0 , 1 , 3 , 4 , 5 ])
267+ assert (get_test_graph_3 ().topological_sort () == [5 , 3 , 2 , 4 , 7 , 8 , 11 ])
268+
269+
270+ def main ():
271+ test_dfs ()
272+ test_bfs ()
273+ test_contains_cycle ()
274+ test_topological_sort ()
211275
276+ print ("Tests complete." )
212277
213278if __name__ == "__main__" :
214279 main ()
0 commit comments