def test_all_in_edges_of_node(self): graph = DiGraph() tuple0 = (0, 30, 2) tuple1 = (50, 50, 50) node0 = NodeData(0, tuple0) # node: key=0 tuple=(0, 30, 2) node1 = NodeData(1, tuple0) # node: key=1 tuple=(0, 30, 2) node2 = NodeData(2, tuple1) # node: key=2 tuple=(50, 50, 50) node3 = NodeData(3, tuple1) # node: key=3 tuple=(50, 50, 50) graph.add_node(node0.get_key(), tuple0) # add node0 self.assertEqual({}, graph.all_in_edges_of_node( node0.get_key())) # check the list In empty graph.add_node(node1.get_key(), tuple0) # add node1 graph.add_node(node2.get_key(), tuple1) # add node2 graph.add_node(node3.get_key(), tuple1) # add node3 graph.add_edge(node1.get_key(), node0.get_key(), 10) # connect 1->0 graph.add_edge(node2.get_key(), node0.get_key(), 15) # connect 2->0 graph.add_edge(node3.get_key(), node0.get_key(), 20) # connect 3->0 ans_list_keys = [node1.get_key(), node2.get_key(), node3.get_key()] for i in graph.all_in_edges_of_node(node0.get_key()).keys(): self.assertIn(i, ans_list_keys) graph.remove_node(node2.get_key()) # remove node2 graph.remove_node(node3.get_key()) # remove node3 ans_list_keys = [node1.get_key()] for i in ans_list_keys: self.assertIn(i, graph.all_in_edges_of_node(node0.get_key()).keys())
def test_all_edges(self): G = DiGraph() G.add_node(0) G.add_node(1) G.add_node(2) G.add_edge(0, 1, 10) G.add_edge(2, 1, 10) self.assertEqual(len(G.all_in_edges_of_node(1)), 2) self.assertEqual(len(G.all_out_edges_of_node(1)), 0) self.assertEqual(len(G.all_in_edges_of_node(0)), 0) self.assertEqual(len(G.all_out_edges_of_node(0)), 1)
def test_all_out_edges_of_node(self): graph = DiGraph() self.assertTrue(graph.add_node(0)) self.assertTrue(graph.add_node(1)) self.assertTrue(graph.add_node(2)) self.assertTrue(graph.add_node(3)) self.assertTrue(graph.add_edge(1, 2, 0)) self.assertTrue(graph.add_edge(2, 1, 1)) edge = graph.all_in_edges_of_node(1) self.assertEqual(edge[2], 1) edge = graph.all_in_edges_of_node(2) self.assertEqual(edge[1], 0)
def test_all_in_edges_of_node(self): g = DiGraph() g.add_node(1) g.add_node(2) g.add_node(3) g.add_node(4) g.add_edge(1, 2, 3) g.add_edge(2, 3, 2) g.add_edge(3, 4, 3) g.add_edge(4, 1, 2.5) self.assertDictEqual({4: 2.5}, g.all_in_edges_of_node(1)) g.add_edge(2, 1, 0.5) self.assertDictEqual({2: 0.5, 4: 2.5}, g.all_in_edges_of_node(1))
def test_remove_edge(self): graph = DiGraph() graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_edge(1, 2, 1) graph.add_edge(1, 3, 1) self.assertEqual(graph.all_in_edges_of_node(2).get(1), 1) self.assertEqual(graph.all_out_edges_of_node(1).get(2), 1) graph.remove_edge(1, 2) self.assertEqual(graph.all_in_edges_of_node(2).get(1), None) self.assertEqual(graph.all_out_edges_of_node(1).get(2), None) self.assertEqual(graph.e_size(), 1)
def test_v_e_size_removes_and_add(self): graph = DiGraph() self.assertEqual(False, self.graph.add_edge(1, 7, -1)) self.assertEqual(0, graph.e_size()) self.assertEqual(0, graph.v_size()) self.assertEqual(0, graph.get_mc()) self.assertEqual(False, graph.remove_edge(1, 3)) self.assertEqual({}, graph.all_out_edges_of_node(3)) self.assertEqual({}, graph.all_in_edges_of_node(3)) self.assertEqual(14, self.graph.v_size()) self.assertEqual(24, self.graph.e_size()) self.assertEqual(38, self.graph.get_mc()) self.assertEqual(True, self.graph.remove_node(4)) self.assertEqual(39, self.graph.get_mc()) self.assertEqual(True, self.graph.remove_edge(1, 2)) self.graph.remove_edge(11, 10) self.assertEqual(False, self.graph.remove_node(15)) self.assertEqual(False, self.graph.remove_node(0)) self.assertEqual(False, self.graph.remove_node(-1)) self.assertEqual(False, self.graph.remove_edge(11, 11)) self.assertEqual(False, self.graph.remove_edge(6, 5)) self.assertEqual(17, self.graph.e_size()) self.assertEqual(13, self.graph.v_size()) self.graph.add_node(99) self.assertEqual(14, self.graph.v_size()) self.graph.add_edge(99, 10, 5) self.graph.add_edge(99, 5, 5) self.graph.add_edge(99, 10, 5) self.graph.add_edge(99, 99, 5) self.graph.add_edge(10, 99, 5) self.graph.add_edge(10, 99, 5) self.assertEqual(20, self.graph.e_size()) self.assertEqual(45, self.graph.get_mc())
def test_add_node1(self): graph = DiGraph() graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_node(4) graph.add_node(5) graph.add_edge(1, 2, 3) graph.add_edge(2, 3, 4) graph.add_edge(3, 4, 10) graph.add_edge(4, 3, 1) graph.add_edge(3, 5, 7) graph.add_edge(5, 1, 1) graph.add_edge(1, 5, 2) self.assertEqual(12, graph.get_mc()) self.assertEqual(5, graph.v_size()) self.assertEqual(7, graph.e_size()) keys = [1, 2, 3, 4, 5] self.assertEqual(keys, list(graph.get_all_v().keys())) self.assertEqual({2: 4, 4: 1}, graph.all_in_edges_of_node(3)) self.assertEqual({4: 10, 5: 7}, graph.all_out_edges_of_node(3)) graph.remove_edge(5, 1) self.assertEqual(6, graph.e_size()) self.assertEqual(0, len(graph.all_out_edges_of_node(5))) self.assertEqual(13, graph.get_mc()) graph.remove_node(3) self.assertEqual(4, graph.v_size()) self.assertEqual(2, graph.e_size()) self.assertEqual(0, len(graph.all_out_edges_of_node(4))) self.assertEqual(14, graph.get_mc())
def check0(): """ This function tests the naming (main methods of the DiGraph class, as defined in GraphInterface. :return: """ g = DiGraph() # creates an empty directed graph for n in range(4): g.add_node(n) g.add_edge(0, 1, 1) g.add_edge(1, 0, 1.1) g.add_edge(1, 2, 1.3) g.add_edge(2, 3, 1.1) g.add_edge(1, 3, 1.9) g.remove_edge(1, 3) g.add_edge(1, 3, 10) print(g) # prints the __repr__ (func output) print(g.get_all_v()) # prints a dict with all the graph's vertices. print(g.all_in_edges_of_node(1)) print(g.all_out_edges_of_node(1)) g_algo = GraphAlgo(g) g_algo.save_to_json('graph.json') g_algo2 = GraphAlgo() g_algo2.load_from_json('graph.json') g_algo2.save_to_json('graphAlgo2.json') print(g_algo.shortest_path(0, 3)) g_algo.plot_graph()
def test_all_out_edges_of_node(self): graph = DiGraph() for i in range(0, 20): graph.add_node(i) for i in range(0, 10): graph.add_edge(i, i + 1, 2) for i in graph.all_in_edges_of_node(10): self.assertTrue(10 in graph.all_out_edges_of_node(i))
def test_all_in_edges_of_node(self): g0 = DiGraph() for i in range(0, 10): g0.add_node(i) g0.add_edge(4, 3, 1) g0.add_edge(4, 2, 1) g0.add_edge(2, 4, 1) g0.add_edge(1, 2, 1) g0.add_edge(5, 3, 1) g0.add_edge(2, 5, 1) self.assertEqual(2, len(g0.all_in_edges_of_node(3))) g0.add_edge(1, 3, 1) self.assertEqual(3, len(g0.all_in_edges_of_node(3))) g0.add_edge(1, 3, 1) # already existed self.assertEqual(3, len(g0.all_in_edges_of_node(3))) g0.remove_edge(1, 3) # check if this dict updates after removing edge self.assertEqual(2, len(g0.all_in_edges_of_node(3)))
class TestDiGraph(TestCase): def setUp(self) -> None: self.g = DiGraph() for i in range(5): self.g.add_node(i) self.g.add_edge(1, 2, 1) self.g.add_edge(1, 3, 1) self.g.add_edge(1, 4, 1) self.g.add_edge(2, 1, 1) self.g.add_edge(2, 0, 1.5) self.g.add_edge(3, 1, 1) self.g.add_edge(4, 0, 4.8) self.g.add_edge(4, 2, 1) def test_v_size(self): self.assertEqual(5, self.g.v_size()) def test_e_size(self): self.assertEqual(8, self.g.e_size()) def test_get_mc(self): self.assertEqual(13, self.g.get_mc()) def test_add_edge(self): self.assertFalse(self.g.add_edge(9, 5, 0.35)) self.assertTrue(self.g.add_edge(0, 2, 0.93)) def test_add_node(self): self.assertFalse(self.g.add_node(0)) self.assertTrue(self.g.add_node(5)) self.assertFalse(self.g.add_node(5)) def test_remove_node(self): self.assertFalse(self.g.remove_node(6)) self.assertTrue(self.g.remove_node(4)) self.assertEqual(5, self.g.e_size()) def test_remove_edge(self): self.assertFalse(self.g.remove_edge(0, 7)) self.assertTrue(self.g.remove_edge(1, 2)) self.assertEqual(7, self.g.e_size()) def test_all_in_edges_of_node(self): self.assertEqual({2: 1.5, 4: 4.8}, self.g.all_in_edges_of_node(0)) def test_all_out_edges_of_node(self): self.assertEqual({2: 1, 3: 1, 4: 1}, self.g.all_out_edges_of_node(1)) def test_get_all_v(self): self.assertEqual(5, len(self.g.get_all_v())) d = { 0: self.g.get_all_v()[0], 1: self.g.get_all_v()[1], 2: self.g.get_all_v()[2], 3: self.g.get_all_v()[3], 4: self.g.get_all_v()[4] } self.assertEqual(d, self.g.get_all_v())
def test_all_in_edges_of_node(self): graph = DiGraph() graph.add_node(1) graph.add_node(2) graph.add_edge(1, 2, 1) graph.add_edge(2, 1, 1) edges_in = graph.all_in_edges_of_node(1) self.assertEqual(len(edges_in.values()), 1, 'not all nodes returned') self.assertEqual(edges_in.get(2), 1, 'Doesn\'t contain all edges')
def test_all_in_edges_of_node(self): g = DiGraph() g.add_node(1) g.add_node(2) g.add_node(3) g.add_edge(1, 2, 3.3) g.add_edge(2, 1, 3.3) g.add_edge(3, 1, 2.2) self.assertEqual(g.all_in_edges_of_node(2), {1: 3.3})
def test_all_in_edges_of_node(self): graph = DiGraph() graph.add_node(0) graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_edge(0, 1, 5) graph.add_edge(1, 2, 3) graph.add_edge(2, 0, 1) graph.add_edge(2, 1, 4) graph.add_edge(2, 3, 3) graph.add_edge(3, 2, 2) edges_in = graph.all_in_edges_of_node(1) self.assertEqual(len(edges_in.values()), 2, "the number of the edges that in to the node 1") graph.remove_node(2) edges_in = graph.all_in_edges_of_node(1) self.assertEqual(len(edges_in.values()), 1, "the new number of the edges that in to the node 1")
def check(): """ This function tests the naming (main methods of the DiGraph class, as defined in GraphInterface. :return: """ g = DiGraph() # creates an empty directed graph for n in range(100): g.add_node(n) b = g.add_node(1) print("add test (false):" + str(b)) # should return false g.add_edge(0, 1, 1) g.add_edge(1, 0, 1.1) g.add_edge(1, 2, 1.3) g.add_edge(2, 3, 1.1) g.add_edge(1, 3, 1.9) b = g.add_edge(1, 3, 10) print("add update weight (false): ", b) b = g.remove_edge(1, 3) print("remove (true): " + str(b)) # should return true b = g.add_edge(1, 3, 10) print("add after remove (true): ", b) b = g.remove_node(2) print("remove node (true): ", b) b = g.remove_node(12) print("remove node that doesnt exist(false): ", b) b = g.add_edge(2, 3, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 2, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 3, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 13, 1.5) print("add edge of node that doesnt exist (false): ", b) print(g) # prints the __repr__ (func output) print(g.get_all_v()) # prints a dict with all the graph's vertices. print(g.all_in_edges_of_node(1)) print(g.all_out_edges_of_node(1)) """
def test_all_in_edges_of_node(self): graph = DiGraph() for i in range(10): graph.add_node(i) graph.add_edge(1, 2, 1.2) graph.add_edge(1, 3, 1.2) graph.add_edge(1, 4, 1.2) graph.add_edge(1, 5, 1.2) graph.add_edge(1, 5, 1.2) graph.add_edge(9, 1, 14.0) graph.add_edge(9, 1, 14.0) graph.add_edge(8, 1, 15.0) self.assertEqual(2, len(graph.all_in_edges_of_node(1)))
def test_get_all_funcs(self): graph = DiGraph() self.assertEqual({}, graph.all_in_edges_of_node(1)) self.assertEqual({}, graph.all_out_edges_of_node(1)) self.assertEqual([], list(graph.get_all_v().keys())) self.assertEqual([], list(self.graph.all_out_edges_of_node(15))) self.assertEqual([], list(self.graph.all_in_edges_of_node(15))) self.assertEqual({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, self.graph.get_all_v().keys()) self.assertEqual({1, 9, 13}, self.graph.all_in_edges_of_node(5).keys()) self.assertEqual({3, 7, 4}, self.graph.all_in_edges_of_node(9).keys()) self.assertEqual([], list(self.graph.all_in_edges_of_node(1).keys())) self.assertEqual({2, 5}, self.graph.all_out_edges_of_node(1).keys()) self.graph.remove_node(5) self.assertEqual({1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14}, self.graph.get_all_v().keys())
def test_add_edge(self): graph = DiGraph() graph.add_node(1) graph.add_node(2) graph.add_edge(1, 2, 1) self.assertEqual(graph.all_in_edges_of_node(2).get(1), 1, "yalla") self.assertEqual(graph.all_out_edges_of_node(1).get(2), 1, "yalla") graph.add_edge(1, 2, 1) self.assertEqual( graph.all_out_edges_of_node(1).get(2), 1, "failed in add duplicate test") self.assertEqual( graph.all_in_edges_of_node(2).get(1), 1, "failed in add duplicate test") self.assertEqual(graph.e_size(), 1, "failed in add duplicate test") graph.add_edge(1, 1, 1) self.assertEqual( graph.all_out_edges_of_node(1).get(1), None, "failed in add duplicate test") self.assertEqual( graph.all_in_edges_of_node(1).get(1), None, "failed in add duplicate test") self.assertEqual(graph.e_size(), 1, "failed in add duplicate test")
def test_all_in_edges_of_node(self): graph = DiGraph() edges_list_tuple = [] for i in range(5): graph.add_node(i) for s in graph.get_all_v().keys(): for d in graph.get_all_v().keys(): w = random.random() graph.add_edge(s, d, w) edges_list_tuple.append((s, d, w)) for v in graph.get_all_v().keys(): edges_list = [(s, d, w) for s, d, w in edges_list_tuple if d != s and d == v] edge_dict = graph.all_in_edges_of_node(v) for s, d, w in edges_list: self.assertEqual(edge_dict[s], w)
def test_get_edges(self): # check for correct edges' dict values graph = DiGraph() for i in range(6): graph.add_node(i) graph.add_edge(0, 1, 1) graph.add_edge(2, 1, 3) graph.add_edge(3, 1, 4) graph.add_edge(1, 2, 3) graph.add_edge(1, 5, 6) # estimated values check_out = {2: 3, 5: 6} edges_out = graph.all_out_edges_of_node(1) check_in = {0: 1, 2: 3, 3: 4} edges_in = graph.all_in_edges_of_node(1) # check every dictionary values for e in edges_out: self.assertEqual(check_out[e], edges_out[e]) for e in edges_in: self.assertEqual(check_in[e], edges_in[e])
class Test(TestCase): def setUp(self): # graph creator, |V|=7, |E|=18 self.graph = DiGraph() for i in range(7): self.graph.add_node(i) self.graph.add_edge(0, 1, 1) self.graph.add_edge(0, 2, 1) self.graph.add_edge(0, 3, 1) self.graph.add_edge(0, 4, 1) self.graph.add_edge(0, 5, 1) self.graph.add_edge(0, 6, 1) self.graph.add_edge(1, 0, 1) self.graph.add_edge(1, 2, 1) self.graph.add_edge(2, 1, 1) self.graph.add_edge(2, 4, 1) self.graph.add_edge(3, 4, 1) self.graph.add_edge(3, 5, 1) self.graph.add_edge(4, 1, 1) self.graph.add_edge(4, 2, 1) self.graph.add_edge(4, 3, 1) self.graph.add_edge(5, 0, 1) self.graph.add_edge(5, 2, 1) self.graph.add_edge(5, 4, 1) def test_v_size(self): self.assertEqual(7, self.graph.v_size()) # add new node self.assertTrue(self.graph.add_node(7)) self.assertEqual(8, self.graph.v_size()) # add existing node self.assertFalse(self.graph.add_node(0)) self.assertEqual(8, self.graph.v_size()) def test_e_size(self): self.assertEqual(18, self.graph.e_size()) # add new edge self.assertTrue(self.graph.add_edge(6, 5, 1)) self.assertEqual(19, self.graph.e_size()) # add edge that already exists in the graph self.assertFalse(self.graph.add_edge(0, 1, 1)) self.assertEqual(19, self.graph.e_size()) def test_get_all_v(self): nodes = { 0: Node(0), 1: Node(1), 2: Node(2), 3: Node(3), 4: Node(4), 5: Node(5), 6: Node(6) } self.assertEqual(nodes.__repr__(), self.graph.get_all_v().__repr__()) def test_all_in_edges_of_node(self): self.assertEqual({1: 1, 5: 1}, self.graph.all_in_edges_of_node(0)) self.graph.add_node(7) self.assertEqual({}, self.graph.all_in_edges_of_node(7)) self.assertRaises(Exception, self.graph.all_in_edges_of_node, 10) def test_all_out_edges_of_node(self): self.assertEqual({ 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1 }, self.graph.all_out_edges_of_node(0)) self.assertEqual({0: 1, 2: 1}, self.graph.all_out_edges_of_node(1)) self.assertEqual({}, self.graph.all_out_edges_of_node(6)) self.assertRaises(Exception, self.graph.all_in_edges_of_node, 10) def test_get_mc(self): self.assertEqual(25, self.graph.get_mc()) # remove node with edges self.assertTrue(self.graph.remove_node(0)) # mc+=9 , remove node: 1, remove edges out of node 0: 5, remove edges in to node 0: 2 self.assertEqual(34, self.graph.get_mc()) def test_add_edge(self): self.assertEqual(18, self.graph.e_size()) # add new edge self.assertTrue(self.graph.add_edge(6, 5, 1)) self.assertEqual(19, self.graph.e_size()) self.assertEqual(26, self.graph.get_mc()) # add edge that already exists in the graph self.assertFalse(self.graph.add_edge(0, 1, 1)) # add edge between nodes that does not exists in the graph self.assertFalse(self.graph.add_edge(0, 10, 1)) self.assertFalse(self.graph.add_edge(10, 0, 1)) self.assertFalse(self.graph.add_edge(10, 11, 1)) self.assertEqual(19, self.graph.e_size()) self.assertEqual(26, self.graph.get_mc()) def test_add_node(self): self.assertEqual(7, self.graph.v_size()) # add new node self.assertTrue(self.graph.add_node(7)) self.assertEqual(8, self.graph.v_size()) self.assertEqual(26, self.graph.get_mc()) # add existing node self.assertFalse(self.graph.add_node(0)) self.assertEqual(8, self.graph.v_size()) self.assertEqual(26, self.graph.get_mc()) def test_remove_node(self): self.assertEqual(7, self.graph.v_size()) # remove node self.assertTrue(self.graph.remove_node(6)) self.assertEqual(6, self.graph.v_size()) self.assertEqual(27, self.graph.get_mc()) # remove node that does not exists in the graph self.assertFalse(self.graph.remove_node(10)) self.assertEqual(6, self.graph.v_size()) self.assertEqual(27, self.graph.get_mc()) def test_remove_edge(self): self.assertEqual(18, self.graph.e_size()) # remove edge self.assertTrue(self.graph.remove_edge(1, 2)) self.assertEqual(17, self.graph.e_size()) self.assertEqual(26, self.graph.get_mc()) # remove edge that does not exists in the graph self.assertFalse(self.graph.remove_edge(1, 6)) self.assertEqual(17, self.graph.e_size()) self.assertEqual(26, self.graph.get_mc()) def test_get_node(self): node_0 = self.graph.nodes.get(0) self.assertEqual(node_0, self.graph.get_node(0)) self.assertRaises(Exception, self.graph.get_node, 10)
class TestDiGraph(TestCase): def setUp(self) -> None: self.graph = DiGraph() for i in range(4): self.graph.add_node(i) self.graph.add_edge(0, 1, 1) self.graph.add_edge(1, 0, 1) self.graph.add_edge(1, 2, 1) self.graph.add_edge(2, 3, 1) self.graph.add_edge(3, 1, 1) def test_v_size(self): size = self.graph.v_size() expected = 4 self.assertEqual(size, expected) def test_e_size(self): size = self.graph.e_size() expected = 5 self.assertEqual(size, expected) def test_get_all_v(self): all_v = list(self.graph.get_all_v()) expected = [0, 1, 2, 3] self.assertEqual(all_v, expected) def test_get_node(self): in_node = self.graph.get_node(1) not_in_node = self.graph.get_node(10) expected_node_id = 1 self.assertEqual(in_node.get_node_id(), expected_node_id) self.assertEqual(not_in_node, None) def test_all_in_edges_of_node_and_all_out_edges(self): all_in = list(self.graph.all_in_edges_of_node(1)) expected = [0, 3] self.assertEqual(all_in, expected) all_out = list(self.graph.all_out_edges_of_node(1)) expected = [0, 2] self.assertEqual(all_out, expected) def test_has_edge(self): check_edge = self.graph.has_edge(0, 1) self.assertEqual(check_edge, True) check_edge = self.graph.has_edge(2, 1) self.assertEqual(check_edge, False) def test_add_edge_and_remove_edge(self): self.graph.add_edge(1, 3, 1) size = self.graph.e_size() expected = 6 self.assertEqual(size, expected) self.graph.remove_edge(1, 3) size = self.graph.e_size() expected = 5 self.assertEqual(size, expected) def test_add_node_and_remove_node(self): self.graph.add_node(4) size = self.graph.v_size() expected = 5 self.assertEqual(size, expected) self.graph.remove_node(4) size = self.graph.v_size() expected = 4 self.assertEqual(size, expected)
class GraphAlgo(GraphAlgoInterface): """ * 1) This class represents a Graph-Theory Algorithms on a directed weighted graph that is based on the given * GraphAlgoInterface api. * * 2) This class and the algorithm is based on a Tree data structure * * This class contains all the requested methods: * - get_graph * - load * - load_from_json * - save_to_json * - shortestPath * - connected_component * - connected_component by given a vertex * - plot_graph * * Dijkstra's Shortest-Path algorithm: * * * function Dijkstra(Graph,source): * * create vertex set Q * * for each vertex v in Graph: //Initialization * dist[v] <- INFINITY //Unknown distance from source to V * prev[v] <- UNDEFINED //Previous node in optimal path from source * add v to Q //All nodes initially in Q (unvisited nodes) * * dist[source] <- 0 //Distance from source to source * * while Q is not empty: * u <- vertex in Q with min dist[u] //Source node will be selected first * remove u from Q * * * for each neighbor v of u: // where v is still in Q * alt <- dist[u] + length(u,v) * if alt < dist[v]: // A shorter path to v has been found * dist[v] <- alt * prev[v] <- u * * return dist[], prev[] """ def __init__(self, graph: DiGraph = None): """ init method :param graph: """ if graph is None: self.graph = DiGraph() else: self.graph = graph def get_graph(self) -> GraphInterface: """ :return: the directed graph on which the algorithm works on. """ return self.graph def load_from_json(self, file_name: str) -> bool: """ A method that loads the current graph from a json file. in order to implement the function we used the previous assignment's code plus: https://www.geeksforgeeks.org/how-to-convert-python-dictionary-to-json/ https://www.w3schools.com/python/python_try_except.asp https://www.geeksforgeeks.org/read-json-file-using-python/ :param file_name: :return: """ try: with open(file_name, 'r') as file_n: g_s = file_n.read() json_graph = json.loads(g_s) for m in json_graph['Nodes']: key = m.get("id") pos = m.get("pos") if "pos" not in m: node = GNode(key) key = node.get_key() self.graph.add_node(key) else: node = GNode(key) key = node.get_key() self.graph.add_node(key) position = tuple((float, m['pos'].split(','))) self.graph.add_node(key, position) for k in json_graph['Edges']: src = int(k.get('src')) w = float(k.get('w')) dst = int(k.get('dest')) self.graph.add_edge(src, dst, w) file_n.close() return True except OSError: print("File does not exist!\n") return False def save_to_json(self, file_name: str) -> bool: """ A method that saves the current graph into json file. in order to implement the function we used the previous assignment's code plus: https://www.w3schools.com/python/python_try_except.asp https://www.geeksforgeeks.org/saving-text-json-and-csv-to-a-file-in-python/ :param file_name: :return: boolean """ try: with open(file_name, 'w') as file: graph = {"Edges": [], "Nodes": []} for k in self.graph.edges: graph["Edges"].append({ "src": k[0], "w": k[2], "dest": k[1] }) for j in self.graph.vertices: node = self.graph.get_node(j) if node.get_position() is None: graph["Nodes"].append({"id": node.get_key()}) else: position = str(node.get_position()[0]) + "," + str( node.get_position()[1]) + "," + str( node.get_position()[2]) graph["Nodes"].append({ 'pos': position, "id": node.get_key() }) file.write(json.dumps(graph)) file.close() return True except OSError: print("File", file_name, " not found! ") return False def shortest_path(self, id1: int, id2: int) -> (float, list): """ Returns the shortest path from node id1 to node id2 using Dijkstra's Algorithm @param id1: The start node id @param id2: The end node id @return: The distance of the path, a list of the nodes ids that the path goes through Notes: If there is no path between id1 and id2, or one of them dose not exist the function returns (float('inf'),[]) More info: https://en.wikipedia.org/wiki/Dijkstra's_algorithm """ if id1 not in self.graph.vertices or id2 not in self.graph.vertices: return float('inf'), [] if id1 == id2: return 0, [id1] ans = self.dijksytra_algo(id1, id2) return ans def connected_component(self, id1: int) -> list: """ Finds the Strongly Connected Component(SCC) that node id1 is a part of. based on two helping functions below and compare them @param id1: The node id @return: The list of nodes in the SCC Notes: If the graph is None or id1 is not in the graph, the function should return an empty list [] """ component_original = self.connected_component_aid_original_geph(id1) component_revers = self.connected_component_aid_reverse_geph(id1) container = [] for k in component_original: for m in component_revers: if k == m: if k not in container: container.append(k) self.graph.get_node(k).set_info("in") container.sort() return container def connected_component_aid_original_geph(self, id1): """ A method that helps us in connected components by a given node. gets all keys tags of every nodes that are connected to the id1 node :param id1: :return: container """ self.reset_nodes_tags() container = [] pointer = 0 container.append(id1) while pointer < len(container): key = container[pointer] node_neighbors = self.graph.all_out_edges_of_node(key) for m in range(0, len(node_neighbors)): neighbor_key = list(node_neighbors.keys())[m] node_pointer = self.graph.get_node(neighbor_key) if node_pointer.get_tag() == -1: container.append(neighbor_key) node_pointer.set_tag(1) pointer += 1 return container def connected_component_aid_reverse_geph(self, id1): """ A method that helps us in connected components by a given node. gets all keys tags of every nodes that are connected to the id1 node but the only change is that the function reverse the graph :param id1: :return: container """ self.reset_nodes_tags() container = [] pointer = 0 container.append(id1) while pointer < len(container): key = container[pointer] node_neighbors = self.graph.all_in_edges_of_node(key) for m in range(0, len(node_neighbors)): neighbor_key = list(node_neighbors.keys())[m] node_pointer = self.graph.get_node(neighbor_key) if node_pointer.get_tag() == -1: container.append(neighbor_key) node_pointer.set_tag(1) pointer += 1 return container def connected_components(self) -> List[list]: """ Finds all the Strongly Connected Component(SCC) in the graph. check each vertex on the connected_components by given a node @return: The list all SCC Notes: If the graph is None the function should return an empty list [] """ self.reset_nodes_info() ans = [] graph_nodes = self.graph.get_all_v() for n in graph_nodes: if self.graph.get_node(n).get_info() != "in": mid_ans = self.connected_component(n) ans.append(mid_ans) return ans def reset_nodes_info(self) -> None: """ Aid function that walks all over the graph and reset each node's info :return: None """ for k in self.graph.get_all_v(): self.graph.get_node(k).set_info("") def plot_graph(self) -> None: """ Plots the graph. If the nodes have a position, the nodes will be placed there. Otherwise, they will be placed in a random but elegant manner. @return: None """ self.reset_nodes_tags() x = [] y = [] key = [] graph_vertex = self.graph.get_all_v() for i in graph_vertex: node_pointer = self.graph.get_node(i) pos = node_pointer.get_position() if pos is None: node_pointer.set_position(random() * 434, random() * 35, 0) pos = node_pointer.get_position() x.append(pos[0]) y.append(pos[1]) key.append(i) fig, ax = plt.subplots() ax.scatter(x, y) for i in self.graph.edges: src = self.graph.get_node(i[0]) dest = self.graph.get_node(i[1]) src_x = src.get_position()[0] src_y = src.get_position()[1] dest_x = dest.get_position()[0] dest_y = dest.get_position()[1] x_list = [src_x, dest_x] y_list = [src_y, dest_y] ax.annotate("", xy=(dest_x, dest_y), xytext=(src_x, src_y), arrowprops=dict(arrowstyle="->"), color="RED") plt.plot(x_list, y_list, color="CYAN") for i, txt in enumerate(key): ax.annotate(key[i], (x[i], y[i]), color="BLUE") plt.title("Directed Weighted Graph - graph visualization") plt.show() def reset_nodes_tags(self) -> None: """ Aid function that walks all over the graph and reset each node's tag :return: None """ for k in self.graph.get_all_v(): self.graph.get_node(k).set_tag(-1) def dijksytra_algo(self, src, dest) -> (float, list): """ Dijkstra's shortest path algorithm (mentioned above) that is being implemented :param src: :param dest: :return: (float, list) """ self.reset_nodes_tags() paths = {} container = [] pointer = 0 container.append(self.graph.get_node(src)) paths[src] = 0 container[0].set_tag(0) # create a dictionary, a list a variable, put inside the list the src node and resets everything created while pointer < len(container): node_o_pointer = container[pointer] src_key = node_o_pointer.get_key() node_neighbors = self.graph.all_out_edges_of_node(src_key) path_weight = paths[src_key] for k in range(0, len(node_neighbors)): # walks over the node neighbors dest_key = list(node_neighbors.keys())[k] edge_weight = self.graph.get_edge_weight(src_key, dest_key) node_pointer = self.graph.get_node(dest_key) tag = node_pointer.get_tag() if tag != -1: # checks if the node is visited new_path = path_weight + edge_weight if new_path < paths[dest_key]: paths[dest_key] = new_path if node_pointer.get_tag() == -1: # checks if the node is unvisited container.append(node_pointer) paths[dest_key] = path_weight + edge_weight node_pointer.set_tag(0) node_o_pointer.set_tag(1) pointer += 1 if dest not in paths: # if didn't find destination node in paths list return float('inf'), [] ans = [] pointer = 0 key = dest ans.append(key) while src not in ans and pointer < len(ans): key_pointer = ans[pointer] path_key = paths[key_pointer] key_neighbors = self.graph.all_in_edges_of_node(key_pointer) for l in key_neighbors: if l in paths: path_n = paths[l] e_b = self.graph.get_edge_weight(l, key_pointer) if round(e_b + path_n, 7) == round(path_key, 7): ans.append(l) break pointer += 1 return paths[dest], ans
class GraphAlgo(GraphAlgoInterface): def __init__(self, g: tuple = None): if g is None: self.g = DiGraph() else: self.g = g def get_graph(self) -> GraphInterface: return self.g def load_from_json(self, file_name: str): self.g = DiGraph() with open(file_name) as f: data = json.load(f) for n in data['Nodes']: self.g.add_node(n['id']) for e in data['Edges']: self.g.add_edge(e['src'], e['dest'], e['w']) def save_to_json(self, file_name: str): data = {"Edges": [], "Nodes": []} for n in self.g.get_all_v().keys(): data["Nodes"].append({"id": n}) for n in self.g.get_all_v().keys(): for n2, w in self.g.all_out_edges_of_node(n).items(): data["Edges"].append({"src": n, "w": w, "dest": n2}) with open(file_name, 'w+') as f: json.dump(data, f) def shortest_path(self, id1: int, id2: int) -> (float, list): distancedict = {} q = [] list = [] q.append(id1) distancedict.update({id1: 0}) while len(q) != 0: tmp = q.pop(0) for i in self.g.all_out_edges_of_node(tmp): if i not in distancedict: q.append(i) distancedict.update({ i: self.g.all_out_edges_of_node(tmp)[i] + distancedict[tmp] }) elif (self.g.all_out_edges_of_node(tmp)[i] + distancedict[tmp]) < distancedict[i]: q.append(i) distancedict.update({ i: self.g.all_out_edges_of_node(tmp)[i] + distancedict[tmp] }) if not id2 in distancedict: return math.inf, [] tmp2 = id2 list.append(id2) while tmp2 != id1: for i in self.g.all_in_edges_of_node(tmp2): distancedict[i] if self.g.all_out_edges_of_node( i)[tmp2] + distancedict[i] == distancedict[tmp2]: list.append(i) tmp2 = i break list.reverse() return distancedict[id2], list def SCCUtil(self, u): next = 0 nextgroup = 0 index = [None] * self.g.v_size() lowlink = [None] * self.g.v_size() onstack = [False] * self.g.v_size() stack = [] groups = [] groupid = {} work = [(u, 0)] while work: v, i = work[-1] del work[-1] if i == 0: index[v] = next lowlink[v] = next next += 1 stack.append(v) onstack[v] = True recurse = False for j in self.g.all_out_edges_of_node(v).keys(): w = j if index[w] == None: work.append((v, j + 1)) work.append((w, 0)) recurse = True break elif onstack[w]: lowlink[v] = min(lowlink[v], index[w]) if recurse: continue if index[v] == lowlink[v]: com = [] while True: w = stack[-1] del stack[-1] onstack[w] = False com.append(w) groupid[w] = nextgroup if w == v: break groups.append(com) nextgroup += 1 if work: w = v v, _ = work[-1] lowlink[v] = min(lowlink[v], lowlink[w]) return groups def connected_component(self, id1: int): for i in self.SCCUtil(id1): for j in i: if (j == id1): return i return list() def Diff(self, li1, li2): return list(list(set(li1) - set(li2)) + list(set(li2) - set(li1))) def connected_components(self): check = list(self.g.get_all_v().keys()) ans = list() for i in self.g.get_all_v().keys(): obj = self.SCCUtil(i) for j in obj: if check.__contains__(j[0]): j.reverse() ans.append(j) check = self.Diff(check, j) if not self.g.get_all_v().keys(): ans.append(list()) return ans def plot_graph(self): for key, val in self.g.get_all_v().items(): x = val[0] y = val[1] plt.text(x, y, key) for node, _ in self.g.all_out_edges_of_node(key).items(): x2, y2 = self.g.get_all_v()[node] x1, y1 = val plt.plot([x1, x2], [y1, y2], marker='o') plt.show()
class TestDiGraph(TestCase): def setUp(self) -> None: self.my_graph = DiGraph() for i in range(5): self.my_graph.add_node(i) self.my_graph.add_edge(0, 1, 3) self.my_graph.add_edge(0, 2, 1) self.my_graph.add_edge(2, 0, 9) self.my_graph.add_edge(1, 2, 20) self.my_graph.add_edge(1, 3, 5) self.my_graph.add_edge(1, 4, 7) self.my_graph.add_edge(3, 4, 55) self.my_graph.add_edge(4, 3, 34) def test_has_edge(self): self.assertTrue(self.my_graph.has_edge(0, 1)) self.assertFalse(self.my_graph.has_edge(1, 0)) self.assertFalse(self.my_graph.has_edge(3, 3)) self.assertTrue(self.my_graph.has_edge(4, 3)) def test_v_size(self): vertices = self.my_graph.get_all_v() self.assertEqual(len(vertices.keys()), self.my_graph.vertices_total) def test_e_size(self): self.my_graph.remove_edge(0, 2) self.assertEqual(7, self.my_graph.e_size()) def test_get_all_v(self): self.assertEqual(self.my_graph.get_all_v().keys(), {0, 1, 2, 3, 4}) def test_all_in_edges_of_node(self): self.assertEqual(self.my_graph.all_in_edges_of_node(0).keys(), {2}) self.assertEqual(self.my_graph.all_in_edges_of_node(1).keys(), {0}) self.assertEqual(self.my_graph.all_in_edges_of_node(2).keys(), {0, 1}) self.assertEqual(self.my_graph.all_in_edges_of_node(3).keys(), {1, 4}) self.assertEqual(self.my_graph.all_in_edges_of_node(4).keys(), {1, 3}) def test_all_out_edges_of_node(self): self.assertEqual(self.my_graph.all_out_edges_of_node(0).keys(), {1, 2}) self.assertEqual( self.my_graph.all_out_edges_of_node(1).keys(), {2, 3, 4}) self.assertEqual(self.my_graph.all_out_edges_of_node(2).keys(), {0}) self.assertEqual(self.my_graph.all_out_edges_of_node(3).keys(), {4}) self.assertEqual(self.my_graph.all_out_edges_of_node(4).keys(), {3}) def test_get_mc(self): self.g = DiGraph() for i in range(10): self.g.add_node(i) self.assertEqual(self.g.get_mc(), 10) for i in range(9): self.g.add_edge(i, i + 1, i + 1) self.assertEqual(self.g.get_mc(), 19) for i in range(6, 10): self.g.remove_node(i) self.assertEqual(self.g.get_mc(), 23) def test_add_edge(self): num_of_edges = self.my_graph.e_size() self.my_graph.add_edge(2, 4, 100) self.my_graph.remove_edge(2, 4) self.assertEqual(self.my_graph.e_size(), num_of_edges) self.assertFalse(self.my_graph.add_edge(11, 14, 55)) def test_add_node(self): first_mc = self.my_graph.get_mc() num_of_nodes = self.my_graph.v_size() self.my_graph.add_node(2) self.assertEqual(first_mc, self.my_graph.get_mc()) self.assertEqual(num_of_nodes, self.my_graph.v_size()) self.my_graph.add_node(6) self.assertEqual(first_mc + 1, self.my_graph.get_mc()) self.assertEqual(num_of_nodes + 1, self.my_graph.v_size()) def test_remove_node(self): self.my_graph.remove_node(1) self.assertEqual(4, self.my_graph.v_size()) self.assertEqual(4, self.my_graph.e_size()) def test_remove_edge(self): self.my_graph.remove_edge(0, 2) self.assertEqual(self.my_graph.e_size(), 7)
def check(): """ This function tests the naming (main methods of the DiGraph class, as defined in GraphInterface. :return: """ g = DiGraph() # creates an empty directed graph for n in range(5): g.add_node(n) b = g.add_node(1) print("add test (false):" + str(b)) # should return false g.add_edge(0, 1, 1) g.add_edge(1, 0, 1.1) g.add_edge(1, 2, 1.3) g.add_edge(2, 3, 1.1) g.add_edge(1, 3, 1.9) b = g.add_edge(1, 3, 10) print("add update weight (false): ", b) b = g.remove_edge(1, 3) print("remove (true): " + str(b)) # should return true b = g.add_edge(1, 3, 10) print("add after remove (true): ", b) b = g.remove_node(2) print("remove node (true): ", b) b = g.remove_node(12) print("remove node that doesnt exist(false): ", b) b = g.add_edge(2, 3, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 2, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 3, 1.5) print("add edge of node that doesnt exist (false): ", b) b = g.add_edge(3, 13, 1.5) print("add edge of node that doesnt exist (false): ", b) print(g) # prints the __repr__ (func output) print(g.get_all_v()) # prints a dict with all the graph's vertices. print(g.all_in_edges_of_node(1)) print(g.all_out_edges_of_node(1)) """ output: g -> Graph: |V|=3 , |E|=3 {0: 0: score inf, 1: 1: score inf, 2: 2: score inf, 3: 3: score inf} {0: 1} {0: 1.1, 3: 10} """ g_algo = GraphAlgo(g) b = g_algo.save_to_json('../data/test_json') print("save: ", b) # print(g_algo.shortest_path(0, 3)) # test shortest path dist, path = g_algo.shortest_path(0, 3) print(f"test shortest path < 0 to 3> -> (2.3, [0,1,2,3]) = {dist}, {path}") dist, path = g_algo.shortest_path(0, 50) print(f"test shortest path < 0 to 50> -> (inf, []) = {dist}, {path}") # dist, path = g_algo.shortest_path(20, 2) # print(dist, path) # dist, path = g_algo.shortest_path(2, 20) # print(dist, path) print(f"test SCC from node 0 -> [0, 1] = {g_algo.connected_component(0)}") g_ = GraphAlgo() g_.load_from_json('../data/A5') load_g = g_.get_graph() print(load_g) print(load_g.get_all_v()) # prints a dict with all the graph's vertices. print(load_g.all_in_edges_of_node(1)) print(load_g.all_out_edges_of_node(1)) g_.plot_graph()
class TestDiGraph(TestCase): def setUp(self) -> None: self.graph = DiGraph() for vertex in range(7): self.graph.add_node(vertex) self.graph.add_edge(0, 3, 3) self.graph.add_edge(1, 3, 1) self.graph.add_edge(2, 4, 1.99) self.graph.add_edge(3, 2, 7) self.graph.add_edge(3, 4, 1.2) self.graph.add_edge(4, 6, 1.99) self.graph.add_edge(4, 5, 1.8) self.graph.add_edge(6, 2, 1) self.graph.add_edge(6, 5, 9) def test_add_node(self): self.assertFalse(self.graph.add_node(0)) def test_get_node(self): self.assertFalse(self.graph.get_node(100)) self.assertTrue(self.graph.get_node(3)) def test_add_edge(self): self.assertFalse(self.graph.add_edge(1, 4, -9)) self.assertFalse(self.graph.add_edge(93, 4, -9)) self.assertTrue(self.graph.add_edge(1, 3, 0.34)) print(self.graph.edges) def test_all_in_edges_of_node(self): actual = list(self.graph.all_in_edges_of_node(2).keys()) expected = [3, 6] self.assertEqual(actual, expected) self.assertIsNone(self.graph.all_in_edges_of_node(90)) def test_all_out_edges_of_node(self): actual = list(self.graph.all_out_edges_of_node(4)) expected = [6, 5] self.assertEqual(actual, expected) self.assertIsNone(self.graph.all_out_edges_of_node(90)) actual_weight = self.graph.getEdge(4, 6) expected = 1.99 self.assertEqual(actual_weight, expected) def test_remove_edge(self): tup = (3, 2, self.graph.getEdge(3, 2)) self.assertFalse(self.graph.remove_edge(0, 31)) self.assertTrue(self.graph.remove_edge(3, 2)) actual = self.graph.e_size() expected = 8 self.assertEqual(actual, expected) self.assertNotIn(tup, list(self.graph.edges)) def test_remove_node(self): self.assertFalse(self.graph.remove_node(31)) self.graph.remove_node(3) actual = self.graph.v_size() expected = 6 self.assertEqual(actual, expected) self.assertNotIn(3, list(self.graph.adjacency)) self.assertNotIn(3, list(self.graph.vertices)) def test_graph_transpose(self): graph_transpose = self.graph.graph_transpose() actual = list(self.graph.edges) expected = [] for source, destination, weight in graph_transpose.edges: expected.append((destination, source, weight)) self.assertListEqual(actual, expected) def test_v_size(self): actual = self.graph.v_size() expected = 7 self.assertEqual(actual, expected) self.graph.remove_node(900) self.assertEqual(actual, expected) def test_e_size(self): actual = self.graph.e_size() expected = 9 self.assertEqual(actual, expected) self.graph.remove_edge(0, 900) self.assertEqual(actual, expected) def test_get_mc(self): actual = self.graph.mc expected = 16 self.assertEqual(actual, expected) self.graph.remove_node(5) actual = self.graph.mc expected = 19 self.assertEqual(actual, expected) def test_get_all_v(self): actual = list(self.graph.get_all_v()) expected = [0, 1, 2, 3, 4, 5, 6] self.assertListEqual(actual,expected) def test_reset(self): for vertex in self.graph.vertices.values(): vertex.setInfo("visited") self.graph.Reset() actual = 0 for vertex in self.graph.vertices.values(): if vertex.getInfo() == "unvisited": actual = actual + 1 expected = 7 self.assertEqual(actual, expected)
def test_empty_list(self): g = DiGraph() g.add_node(1) self.assertEqual(g.all_in_edges_of_node(1), {})
class MyTestCase(unittest.TestCase): def setUp(self) -> None: self.graph = DiGraph() for i in range(5): self.graph.add_node(i) self.graph.add_edge(0, 1, 1.0) self.graph.add_edge(0, 2, 1.1) self.graph.add_edge(1, 3, 1.2) self.graph.add_edge(1, 4, 1.3) self.graph.add_edge(2, 0, 1.4) self.graph.add_edge(2, 3, 1.5) self.graph.add_edge(3, 1, 1.5) self.graph.add_edge(3, 4, 1.6) self.graph.add_edge(4, 0, 1.7) self.graph.add_edge(4, 1, 1.8) self.graph.add_edge(4, 3, 1.9) def test_v_size(self): self.assertEqual(5, self.graph.v_size()) self.assertTrue(self.graph.add_node(5)) self.assertEqual(6, self.graph.v_size()) self.assertFalse(self.graph.add_node(1)) self.assertEqual(6, self.graph.v_size()) self.assertTrue(self.graph.add_node(6)) self.assertEqual(7, self.graph.v_size()) def test_e_size(self): self.assertEqual(11, self.graph.e_size()) self.assertFalse(self.graph.add_edge(4, 3, 51.12)) self.assertEqual(11, self.graph.e_size()) self.assertTrue(self.graph.remove_node(1)) self.assertEqual(6, self.graph.e_size()) def test_add_node(self): self.assertEqual(5, self.graph.v_size()) self.assertTrue(self.graph.add_node(13)) self.assertEqual(6, self.graph.v_size()) self.assertEqual(17, self.graph.get_mc()) self.assertFalse(self.graph.add_node(4)) self.assertEqual(17, self.graph.get_mc()) def test_remove_node(self): self.assertEqual(16, self.graph.get_mc()) self.assertEqual(5, self.graph.v_size()) self.assertTrue(self.graph.remove_node(1)) self.assertEqual(4, self.graph.v_size()) self.assertEqual(17, self.graph.get_mc()) self.assertFalse(self.graph.remove_node(9)) self.assertEqual(4, self.graph.v_size()) self.assertEqual(17, self.graph.get_mc()) def test_add_edge(self): self.assertEqual(11, self.graph.e_size()) self.assertTrue(self.graph.add_edge(0, 3, 4.99)) self.assertEqual(12, self.graph.e_size()) self.assertEqual(17, self.graph.get_mc()) self.assertFalse(self.graph.add_edge(1, 4, 3.99)) self.assertFalse(self.graph.add_edge(4, 51, 1)) self.assertFalse(self.graph.add_edge(51, 4, 1)) self.assertFalse(self.graph.add_edge(51, 12, 13)) self.assertEqual(12, self.graph.e_size()) self.assertEqual(17, self.graph.get_mc()) def test_remove_edge(self): self.assertEqual(11, self.graph.e_size()) self.assertTrue(self.graph.remove_edge(4, 3)) self.assertEqual(10, self.graph.e_size()) self.assertEqual(17, self.graph.get_mc()) self.assertFalse(self.graph.remove_edge(3, 2)) self.assertEqual(10, self.graph.e_size()) self.assertEqual(17, self.graph.get_mc()) def test_all_in_edges_of_node(self): self.assertIsNot({}, self.graph.all_in_edges_of_node(1)) self.assertIsNot({}, self.graph.all_in_edges_of_node(2)) self.assertIsNot({}, self.graph.all_in_edges_of_node(3)) self.assertIsNot({}, self.graph.all_in_edges_of_node(4)) self.assertTrue(self.graph.remove_edge(0, 2)) self.assertEqual({}, self.graph.all_in_edges_of_node(2)) def test_all_out_edges_of_node(self): self.assertIsNotNone(self.graph.all_out_edges_of_node(1)) self.assertIsNotNone(self.graph.all_out_edges_of_node(2)) self.assertIsNotNone(self.graph.all_out_edges_of_node(3)) self.assertIsNotNone(self.graph.all_out_edges_of_node(4)) self.assertIsNone(self.graph.all_out_edges_of_node(10)) self.assertIsNone(self.graph.all_out_edges_of_node(22)) def test_get_mc(self): self.assertEqual(16, self.graph.get_mc())
class GraphAlgo(GraphAlgoInterface): def __init__(self, graph: DiGraph = None): if graph is None: graph = DiGraph() self.G = graph def get_graph(self) -> GraphInterface: return self.G def load_from_json(self, file_name: str) -> bool: """create a graph using a saved text file by using the key words "Nodes" and "Edges" then split the string by , to get the X Y Z and creating a new node and adding it to the graph connects the nodes by Edges and w for weight src and dest""" self.G = DiGraph() try: with open(file_name, "r") as file: x = json.load(file) for node in x["Nodes"]: if node.__contains__("pos"): new_pos = [ float(i) for i in node["pos"].split(",", maxsplit=2) ] self.G.add_node(node["id"], (new_pos[0], new_pos[1], new_pos[2])) else: self.G.add_node(node["id"]) if x.__contains__("Edges"): for edge in x["Edges"]: self.G.add_edge(edge["src"], edge["dest"], edge["w"]) return True except IOError as e: print(e) return False def save_to_json(self, file_name: str) -> bool: """save a graph to a text file and saving his Nodes and Edges for the nodes well save the pos and their key for the edges well save the src dest and edge weight""" graph_dict = {} edge_list = [] for i in self.G.oute.keys(): for j in self.G.oute[i].keys(): edge_map = {'src': i, 'w': self.G.oute[i][j], 'dest': j} edge_list.append(edge_map) try: with open(file_name, "w") as file: graph_dict["Edges"] = edge_list graph_dict["Nodes"] = [i for i in self.G.graph.values()] json.dump(graph_dict, default=lambda m: m.as_dict(), fp=file) return True except IOError as e: print(e) return False def shortest_path(self, id1: int, id2: int) -> (float, list): """returns a list of nodes that represents the shortest path between tow nodes and the distance as well using Dijkstra algorithm is an algorithm to fined the shortest path between nodes(by weight). this method find the shortest distance by weight from src node to all the node in the graph. this method based on 4 data structure path(list) , unused(PriorityQueue), used(list) and nodePar(dict). first add the src node to unused PriorityQueue and set is weight to 0, continue while unused is not empty, iterate throw all it's neighbors and every node that isnt with inf weight if the node weight is bigger then his father weight + the edge weight or node weight is inf replace the node weight with his father + the edge between the node and his father. (skip this step for the father node). add to unused PriorityQueue , same for all neighbors. after that pull the next node from unused, because of the PriorityQueue every next node on the list will be with the lightest weight. after iterate throw all the graph all the nodes will be in the nodeDis Hashmap and contain in the value their min weight from src node. also the nodePar will contain every node and his father when called from shortestPath method. now that nodePar is full we can go from the dest node by pointer back until well get to the src node while we adding the nodes the pointer points on to a list which will be the shortest path list then we return this list(nodes we need to go for the shortest path) and the weight of the dest(the distance of that path)""" if id1 not in self.G.get_all_v() or id2 not in self.G.get_all_v(): tmp = (math.inf, []) return tmp used = [] unused = queue.PriorityQueue() nodePar = {} path = [] self.G.graph.get(id1).Weight = 0.0 unused.put(self.G.graph.get(id1)) while not unused.empty(): t = unused.get() if t.id == id2: break if t.id in used: continue used.append(t.id) for Nei in self.G.all_out_edges_of_node(t.id): tempNeiDis = self.G.graph.get(Nei).Weight # nodeDis.get(Nei) tDis = self.G.graph.get(t.id).Weight EdgeDis = self.G.oute.get(t.id).get(Nei) if tempNeiDis > (tDis + EdgeDis): self.G.graph.get(Nei).Weight = tDis + EdgeDis unused.put(self.G.graph.get(Nei)) nodePar[Nei] = t if self.G.graph.get(id2).Weight == math.inf: self.reset_w() return math.inf, path pointernode = self.G.graph.get(id2) path.append(pointernode.id) while pointernode.id is not id1: pointernode = nodePar.get(pointernode.id) path.append(pointernode.id) path.reverse() res = self.G.graph.get(id2).Weight self.reset_w() return res, path def connected_component(self, id1: int) -> list: """returns the Strongly Connected Component(SCC) that node id1 is a part of by creating to sets the first one will be filled with the nodes ids that he can get to the second one will be filled with the nodes that can get to him then well return the intersection of those two lists""" if id1 not in self.G.get_all_v(): return [] connected1 = set() connected_to = [] connected_from = [] connected1.add(id1) while len(connected1) > 0: for node in self.G.all_out_edges_of_node(connected1.pop()): if self.G.graph.get(node).Weight == math.inf: self.G.graph.get(node).Weight = 0 connected1.add(node) connected_to.append(node) connected1.add(id1) while len(connected1) > 0: for node in self.G.all_in_edges_of_node(connected1.pop()): if self.G.graph.get(node).Tag == -1: self.G.graph.get(node).Tag = 0 connected1.add(node) connected_from.append(node) res = list(set(connected_from).intersection(connected_to)) for node in self.G.get_all_v().values(): node.Weight = math.inf node.Tag = -1 if len(res) == 0: res.append(id1) return res def connected_components(self) -> List[list]: """returns all the Strongly Connected Component(SCC) in the graph. returns by creating a set of all the nodes keys and every time send the first node on this list to connected_component(node id) and save that list in a list of lists then removing all the nodes that are in that list from the sets of all nodes and sends the next one untill the set of all nodes is empty and we have list of lists of the strongly connected component in the graph.""" all_nodes = set(self.G.get_all_v().keys()) res = [] if len(all_nodes) == 0: return res while len(all_nodes) > 0: list1 = self.connected_component(all_nodes.pop()) res.append(list1) all_nodes = all_nodes - (set(list1)) return res def plot_graph(self) -> None: """this function draws the graph by using mat_plot_lib we add every node by his pos and every edge by it src and dest(we draw a line between them)""" x = [i.pos[0] for i in self.G.get_all_v().values()] y = [i.pos[1] for i in self.G.get_all_v().values()] plt.plot(x, y, "o") for i in self.G.get_all_v().values(): for j in self.G.all_out_edges_of_node(i.id): x1 = i.pos[0] y1 = i.pos[1] x2 = self.G.graph[j].pos[0] y2 = self.G.graph[j].pos[1] plt.annotate("", xy=(x1, y1), xytext=(x2, y2), arrowprops=dict(arrowstyle="->")) plt.show() def reset_w(self): """resets all the nodes weight to inf""" for node in self.G.get_all_v().values(): node.Weight = math.inf