def test_undirected_graph_dijkstra(self): """ Perform Dijkstra's algorithm on an undirected graph """ """ 1_ E 1_ E | / | / A- 1 -B- 5 -D A- 3 -B- 5 -D \ | \ | 2 0 2 -2 \ | \ | C C """ g = UndirectedGraph() g.add_vertex(v_val='A') g.add_vertex(v_val='B') g.add_vertex(v_val='C') g.add_vertex(v_val='D') g.add_vertex(v_val='E') g.add_edge(('A', 'A'), attrs={'weight': 1}) g.add_edge(('A', 'B'), attrs={'weight': 1}) g.add_edge(('A', 'C'), attrs={'weight': 2}) g.add_edge(('B', 'C'), attrs={'weight': 0}) g.add_edge(('B', 'D'), attrs={'weight': 5}) negative_weight_g = g.clone() negative_weight_g.get_edge(('A', 'B')).set('weight', 3) negative_weight_g.get_edge(('B', 'C')).set('weight', -2) missing_weight_g = g.clone() missing_weight_g.get_edge(('A', 'B')).set('weight', None) self.assertEqual(g.dijkstra('A', goal_val='A'), ['A']) self.assertEqual(g.dijkstra('A', goal_val='B'), ['A', 'B']) self.assertEqual(g.dijkstra('A', goal_val='C'), ['A', 'B', 'C']) self.assertEqual(g.dijkstra('A', goal_val='D'), ['A', 'B', 'D']) self.assertIsNone(g.dijkstra('A', goal_val='E')) # when returning all paths (no goal specified), paths aren't evaluated # until requested, to avoid the O(|V|^2) cost of backtracking |V| paths A_paths = g.dijkstra('A') # request each key _ = [A_paths[v.val] for v in g] self.assertEqual(dict(A_paths), {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'B', 'C'], 'D': ['A', 'B', 'D'], 'E': None}) self.assertEqual(g.dijkstra('A', goal_val='A', return_distances=True), 0) self.assertEqual(g.dijkstra('A', goal_val='B', return_distances=True), 1) self.assertEqual(g.dijkstra('A', goal_val='C', return_distances=True), 1) self.assertEqual(g.dijkstra('A', goal_val='D', return_distances=True), 6) self.assertEqual(g.dijkstra('A', goal_val='E', return_distances=True), float('inf')) self.assertEqual(g.dijkstra('A', return_distances=True), {'A': 0, 'B': 1, 'C': 1, 'D': 6, 'E': float('inf')}) with self.assertRaises(ValueError): negative_weight_g.dijkstra('A') with self.assertRaises(ValueError): missing_weight_g.dijkstra('A')