def edge_disjoint_shortest_pair(g, src, dst): '''Return list of two edge-disjoint paths w/shortest total cost. @param g: NetworkX Graph object @param src: src node label @param dst: dst node label @param paths: two-element list of path lists, arbitrary ordering ''' # 1. Use BFS to get shortest path. shortest_path = BFS(g, src, dst) # 2. Replace each edge of the shortest path (equivalent to two oppositely # directed arcs) by a single arc directed toward the source vertex. # 3. Make the length of each of the above arcs negative. g2 = flip_and_negate_path(g, shortest_path) # 4. Run the modified Dijkstra or the BFS algorithm again and from the # source vertex to the destination vertex in the above modified graph. shortest_path_2 = BFS(g2, src, dst) first_pathtotal = pathlen(g, shortest_path) + pathlen(g2, shortest_path_2) # 5. Transform to the original graph, and erase any interlacing edges of # the two paths found. Group the remaining edges to obtain the shortest # pair of edge-disjoint paths. path1, path2 = grouped_shortest_pair(g, shortest_path, shortest_path_2) path1len = pathlen(g, path1) path2len = pathlen(g, path2) second_pathtotal = path1len + path2len assert (first_pathtotal == second_pathtotal) return [path1, path2]
def edge_disjoint_shortest_pair(g, src, dst): '''Return list of two edge-disjoint paths w/shortest total cost. @param g: NetworkX Graph object @param src: src node label @param dst: dst node label @param paths: two-element list of path lists, arbitrary ordering ''' # 1. Use BFS to get shortest path. shortest_path = BFS(g, src, dst) # 2. Replace each edge of the shortest path (equivalent to two oppositely # directed arcs) by a single arc directed toward the source vertex. # 3. Make the length of each of the above arcs negative. g2 = flip_and_negate_path(g, shortest_path) # 4. Run the modified Dijkstra or the BFS algorithm again and from the # source vertex to the destination vertex in the above modified graph. shortest_path_2 = BFS(g2, src, dst) first_pathtotal = pathlen(g, shortest_path) + pathlen(g2, shortest_path_2) # 5. Transform to the original graph, and erase any interlacing edges of # the two paths found. Group the remaining edges to obtain the shortest # pair of edge-disjoint paths. path1, path2 = grouped_shortest_pair(g, shortest_path, shortest_path_2) path1len = pathlen(g, path1) path2len = pathlen(g, path2) second_pathtotal = path1len + path2len assert(first_pathtotal == second_pathtotal) return [path1, path2]
def test_example_3_13_a_mod_2(self): '''Example 3.13a on pg 65, mod on pg 78. This example has two equally good path choices, so only check sum of paths. ''' g = graph_fig_3_13_a_mod_2 ed_paths = edge_disjoint_shortest_pair(g, 'A', 'Z') ed_paths_len = sum([pathlen(g, ed_paths[i]) for i in [0, 1]]) exp_paths = [[i for i in 'ABCDEFZ'], [i for i in 'AGDHZ']] exp_paths_len = sum([pathlen(g, exp_paths[i]) for i in [0, 1]]) self.assertEqual(ed_paths_len, exp_paths_len)
def test_example_3_13_a_mod_2(self): '''Example 3.13a on pg 65, mod 2 on pg 78. This example has two equally good path choices (ABIFZ / AGDHZ and ABCDEFZ / AGDHZ), so only check sum of paths. ''' g = graph_fig_3_13_a_mod_2 vd_paths = vertex_disjoint_shortest_pair(g, 'A', 'Z') vd_paths_len = sum([pathlen(g, vd_paths[i]) for i in [0, 1]]) exp_paths = [[i for i in 'ABIFZ'], [i for i in 'AGDHZ']] exp_paths_len = sum([pathlen(g, exp_paths[i]) for i in [0, 1]]) compare_path_lists(self, vd_paths, exp_paths, g, 14) self.assertEqual(vd_paths_len, exp_paths_len)
def compare_path_lists(test, one, two, g = None, total = None): '''Compare two path lists. Useful because shortest path algorithms yield paths in arbitrary orders. @param test: instance of unittest.TestCase @param one: list of path nodes @param two: list of path nodes @param g: optional NetworkX graph for path length verification @param total: optional total length of both paths ''' def make_tuple_set(path_list): return set([tuple(path) for path in path_list]) test.assertEqual(make_tuple_set(one), make_tuple_set(two)) if g: test.assertEqual(total, pathlen(g, one[0]) + pathlen(g, one[1]))
def compare_path_lists(test, one, two, g=None, total=None): '''Compare two path lists. Useful because shortest path algorithms yield paths in arbitrary orders. @param test: instance of unittest.TestCase @param one: list of path nodes @param two: list of path nodes @param g: optional NetworkX graph for path length verification @param total: optional total length of both paths ''' def make_tuple_set(path_list): return set([tuple(path) for path in path_list]) test.assertEqual(make_tuple_set(one), make_tuple_set(two)) if g: test.assertEqual(total, pathlen(g, one[0]) + pathlen(g, one[1]))
def test_example_3_16_a(self): '''Example 3.16a on pg 74.''' g = graph_fig_3_16_a path = BFS(g, 'A', 'Z') self.assertEqual(path, [i for i in 'ABCDEFZ']) self.assertEqual(pathlen(g, path), 6)
def test_example_3_1_a(self): '''Example 3.1a on pg. 41.''' g = graph_fig_3_1_a path = BFS(g, 'A', 'Z') self.assertEqual(path, [i for i in 'ABCDZ']) self.assertEqual(pathlen(g, path), 4)
def test_example_2_6(self): '''Example 2.6 on pg. 35.''' g = graph_fig_2_3 path = BFS(g, 'A', 'Z') self.assertEqual(path, [i for i in 'ADECBZ']) self.assertEqual(pathlen(g, path), 12)