def test_directed_graph_remove_vertex(self): """ Remove vertices from a directed graph """ g = DirectedGraph() g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_vertex(v_val='v2') g.add_edge(('v0', 'v1')) g.add_edge(('v1', 'v2')) g.remove_vertex('v0') self.assertFalse(g.has_vertex('v0')) self.assertTrue(g.has_vertex('v1')) self.assertTrue(g.has_vertex('v2')) self.assertFalse(g.has_edge(('v0', 'v1'))) self.assertFalse(g.has_edge(('v1', 'v0'))) self.assertTrue(g.has_edge(('v1', 'v2'))) g.remove_vertex('v1') self.assertFalse(g.has_vertex('v0')) self.assertFalse(g.has_vertex('v1')) self.assertTrue(g.has_vertex('v2')) self.assertFalse(g.has_edge(('v0', 'v1'))) self.assertFalse(g.has_edge(('v1', 'v1'))) self.assertFalse(g.has_edge(('v1', 'v2')))
def test_directed_graph_edge_already_exists_exception(self): """ A directed graph should not be able to add an edge that already exists in the graph """ g = DirectedGraph() g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_edge(('v0', 'v1')) with self.assertRaises(ValueError): g.add_edge(('v0', 'v1'))
def test_directed_graph_add_edge(self): """ Add edges to a directed graph """ g = DirectedGraph() g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_edge(('v0', 'v0'), attrs={'weight': 5}) g.add_edge(('v0', 'v1'), attrs={'weight': 7}) e00 = g.get_edge(('v0', 'v0')) e01 = g.get_edge(('v0', 'v1')) self.assertTrue(g.has_edge(('v0', 'v0'))) self.assertTrue(g.has_edge(('v0', 'v1'))) self.assertFalse(g.has_edge(('v0', 'v2'))) self.assertFalse(g.has_edge(('v1', 'v0'))) self.assertEqual(e00.get('weight'), 5) self.assertEqual(e01.get('weight'), 7)
def test_directed_graph_vertices_and_edges(self): """ Get directed graphs' vertices and edges properties """ g = DirectedGraph() g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_edge(('v0', 'v1')) v0 = g.get_vertex('v0') v1 = g.get_vertex('v1') e01 = g.get_edge(('v0', 'v1')) self.assertEqual(set(g.vertices), set([v0, v1])) self.assertEqual(set(g.edges), set([e01])) with self.assertRaises(AttributeError): g.vertices = set() with self.assertRaises(AttributeError): g.edges = set()
def test_directed_graph_iteration(self): """ Iterate through a directed graph """ g = DirectedGraph() counter = 0 for v in g: counter += 1 self.assertEqual(counter, 0) g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_edge(('v0', 'v1')) for v in g: counter += 1 self.assertTrue(g.has_vertex(v.val)) self.assertEqual(counter, 2)
def test_directed_graph_length(self): """ Get the length of a directed graph """ g = DirectedGraph() self.assertEqual(len(g), 0) g.add_vertex(v_val='v0') self.assertEqual(len(g), 1) g.add_vertex(v_val='v1') g.add_edge(('v0', 'v1')) self.assertEqual(len(g), 2) g.remove_vertex('v0') self.assertEqual(len(g), 1)
def test_directed_graph_search(self): """ Search for paths from a directed vertex to all vertices reachable from it """ """ __ | / | < v0 -> v1 -> v3 \ > v2 """ g = DirectedGraph() g.add_vertex(v_val='v0') g.add_vertex(v_val='v1') g.add_vertex(v_val='v2') g.add_vertex(v_val='v3') g.add_vertex(v_val='v4') g.add_edge(('v0', 'v0')) g.add_edge(('v0', 'v1')) g.add_edge(('v2', 'v0')) g.add_edge(('v1', 'v3')) self.assertEqual(g.search('v0', goal_val='v0'), ['v0']) self.assertEqual(g.search('v0', goal_val='v1'), ['v0', 'v1']) self.assertIsNone(g.search('v0', goal_val='v2')) self.assertEqual(g.search('v0', goal_val='v3'), ['v0', 'v1', 'v3']) self.assertIsNone(g.search('v0', goal_val='v4')) self.assertEqual(g.search('v0'), {'v0': ['v0'], 'v1': ['v0', 'v1'], 'v3': ['v0', 'v1', 'v3']}) self.assertEqual(g.search('v0', goal_val='v0', method='depth_first'), ['v0']) self.assertEqual(g.search('v0', goal_val='v1', method='depth_first'), ['v0', 'v1']) self.assertIsNone(g.search('v0', goal_val='v2', method='depth_first')) self.assertEqual(g.search('v0', goal_val='v3', method='depth_first'), ['v0', 'v1', 'v3']) self.assertIsNone(g.search('v0', goal_val='v4', method='depth_first')) self.assertEqual(g.search('v0', method='depth_first'), {'v0': ['v0'], 'v1': ['v0', 'v1'], 'v3': ['v0', 'v1', 'v3']})
def test_directed_graph_dijkstra(self): """ Perform Dijkstra's algorithm on a directed graph """ """ 1_ E 1_ E | / | / | < | < A- 1 ->B- 5 ->D A- 3 ->B- 5 ->D \ | / \ | / 2 0 1 2 -2 1 \ v / \ v / > C < > C < """ g = DirectedGraph() 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}) g.add_edge(('D', 'C'), attrs={'weight': 1}) 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')