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 rereverseGraph(self, g: DiGraph) -> GraphInterface:
     gr = DiGraph()
     for n in g.get_all_v().values():
         gr.add_node(n.getKey(), n.getLocation())
     for n in g.get_all_v().values():
         for e in g.all_out_edges_of_node(n.getKey()).items(
         ):  # return tuple of pair (other node id, weight))
             gr.add_edge(e[0], n.getKey(), e[1])
     return gr
 def test_add_edge(self):
     graph = DiGraph()
     for i in range(5):
         graph.add_node(i)
     test_dict = {"0": 3.4, "1": 3.5, "2": 5.4, "3": 3.1, "4": 4.5}
     conn_dict = {"0": 1, "1": 2, "2": 3, "3": 4, "4": 0}
     for k in graph.get_all_v().keys():
         graph.add_edge(k, conn_dict[str(k)], test_dict[str(k)])
     for k, v in graph.get_all_v().items():
         weight = v.getWeight(conn_dict[str(k)])
         self.assertEqual(weight, test_dict[str(k)])
 def test_get_all_v(self):
     """
     get_all_v need to return all the vertices in the graph
     """
     g = DiGraph()
     self.assertEqual(g.get_all_v(), {})  # there are no edges in the graph
     g.add_node(1)
     p_node = NodeData(key=1)
     g_vertices = {1: p_node}
     self.assertEqual(g.get_all_v(), g_vertices)
     g.remove_node(1)
     self.assertEqual(g.get_all_v(), {})
Exemple #5
0
 def test_remove_node(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.e_size(), 2)
     self.assertEqual(graph.v_size(), 3)
     graph.remove_node(1)
     self.assertEqual(graph.e_size(), 0)
     self.assertEqual(graph.v_size(), 2)
     self.assertEqual(graph.get_all_v().get(1), None)
     self.assertEqual(graph.get_all_v(), {2: NodeData(2), 3: NodeData(3)})
 def graph_nx(self, graph: DiGraph):
     g = nx.DiGraph()
     for i in graph.get_all_v().keys():
         g.add_node(i)
         for n, w in graph.all_out_edges_of_node(i).items():
             g.add_edge(i, n, weight=w)
     return g
 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)
Exemple #8
0
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()
Exemple #9
0
    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())
Exemple #10
0
 def test_get_all_v(self):
     g0 = DiGraph()
     flag = True
     for i in range(0, 10):
         g0.add_node(i)
     for i in range(0, 10):
         if i not in g0.get_all_v().keys(): flag = False
     self.assertTrue(flag)
Exemple #11
0
 def test_add_node(self):
     graph = DiGraph()
     for i in range(10):
         graph.add_node(i)
     graph.add_node(1, (1, 2, 3))
     for i in range(10):
         self.assertEqual(graph.__contains__(i), True)
     node1 = graph.get_all_v().get(1)
     self.assertEqual(node1.get_pos(), None)
def create_graph(seed, nodes, edges):
    g0 = DiGraph()
    r = rnd(x=seed)
    for i in range(nodes):
        g0.add_node(i, (r.random() * 100, r.random() * 100))
    while edges > 0:
        keys = list(g0.get_all_v().keys())
        s, e = map(r.choice, [keys, keys])
        edges -= g0.add_edge(s, e, r.uniform(1, 2))
    return g0
Exemple #13
0
 def test_get_all_v(self):
     graph = DiGraph()
     graph.add_node(1)
     graph.add_node(2)
     nodes = graph.get_all_v()
     self.assertEqual(len(nodes.values()), 2, 'not all nodes returned')
     self.assertEqual(nodes.get(1), NodeData(1),
                      'Doesn\'t contain all nodes')
     self.assertEqual(nodes.get(2), NodeData(2),
                      'Doesn\'t contain all nodes')
 def test_get_all_v(self):
     graph = DiGraph()
     graph.add_node(0)
     graph.add_node(1)
     graph.add_node(2)
     graph.add_node(3)
     nodes = graph.get_all_v()
     self.assertEqual(len(nodes.values()), 4)
     graph.add_node(3)
     self.assertEqual(len(nodes.values()), 4, "add node that exist")
Exemple #15
0
    def test_load_from_json(self):
        self.assertTrue(self.algorithms.load_from_json("../data/A0"))
        graph_loaded = DiGraph()
        graph_loaded.add_node(0, (35.18753053591606, 32.10378225882353, 0.0))
        graph_loaded.add_node(1, (35.18958953510896, 32.10785303529412, 0.0))
        graph_loaded.add_node(2, (35.19341035835351, 32.10610841680672, 0.0))
        graph_loaded.add_node(3, (35.197528356739305, 32.1053088, 0.0))
        graph_loaded.add_node(4, (35.2016888087167, 32.10601755126051, 0.0))
        graph_loaded.add_node(5, (35.20582803389831, 32.10625380168067, 0.0))
        graph_loaded.add_node(6, (35.20792948668281, 32.10470908739496, 0.0))
        graph_loaded.add_node(7, (35.20746249717514, 32.10254648739496, 0.0))
        graph_loaded.add_node(8, (35.20319591121872, 32.1031462, 0.0))
        graph_loaded.add_node(9, (35.19597880064568, 32.10154696638656, 0.0))
        graph_loaded.add_node(10, (35.18910131880549, 32.103618700840336, 0.0))

        graph_loaded.add_edge(0, 1, 1.4004465106761335)
        graph_loaded.add_edge(0, 10, 1.4620268165085584)
        graph_loaded.add_edge(1, 0, 1.8884659521433524)
        graph_loaded.add_edge(1, 2, 1.7646903245689283)
        graph_loaded.add_edge(2, 1, 1.7155926739282625)
        graph_loaded.add_edge(2, 3, 1.1435447583365383)
        graph_loaded.add_edge(3, 2, 1.0980094622804095)
        graph_loaded.add_edge(3, 4, 1.4301580756736283)
        graph_loaded.add_edge(4, 3, 1.4899867265011255)
        graph_loaded.add_edge(4, 5, 1.9442789961315767)
        graph_loaded.add_edge(5, 4, 1.4622464066335845)
        graph_loaded.add_edge(5, 6, 1.160662656360925)
        graph_loaded.add_edge(6, 5, 1.6677173820549975)
        graph_loaded.add_edge(6, 7, 1.3968360163668776)
        graph_loaded.add_edge(7, 6, 1.0176531013725074)
        graph_loaded.add_edge(7, 8, 1.354895648936991)
        graph_loaded.add_edge(8, 7, 1.6449953452844968)
        graph_loaded.add_edge(8, 9, 1.8526880332753517)
        graph_loaded.add_edge(9, 8, 1.4575484853801393)
        graph_loaded.add_edge(9, 10, 1.022651770039933)
        graph_loaded.add_edge(10, 0, 1.1761238717867548)
        graph_loaded.add_edge(10, 9, 1.0887225789883779)

        self.assertEqual(self.algorithms.get_graph().v_size(),
                         graph_loaded.v_size())
        self.assertEqual(self.algorithms.get_graph().e_size(),
                         graph_loaded.e_size())
        self.assertEqual(self.algorithms.get_graph().get_mc(),
                         graph_loaded.get_mc())
        self.assertListEqual(self.algorithms.get_graph().edges,
                             graph_loaded.edges)
        self.assertEqual(self.algorithms.get_graph().get_all_v().keys(),
                         graph_loaded.get_all_v().keys())
        self.assertEqual(self.algorithms.get_graph().adjacency.keys(),
                         graph_loaded.adjacency.keys())
        self.assertNotEqual(self.algorithms.get_graph(), graph_loaded)
        self.assertEqual(str(self.algorithms.get_graph().vertices),
                         str(graph_loaded.vertices))
        self.assertEqual(str(self.algorithms.get_graph().adjacency),
                         str(graph_loaded.adjacency))
Exemple #16
0
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))
    """
Exemple #17
0
 def test_remove_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, 4, 1)
     g0.add_edge(2, 5, 1)
     g0.remove_node(4)
     self.assertEqual(g0.get_all_v().get(4), None)
     self.assertEqual(0, len(g0.all_out_edges_of_node(5)))
     self.assertEqual(9, g0.v_size())
     self.assertEqual(2, g0.e_size())
     self.assertTrue(g0.remove_node(9))
     self.assertIsNone(g0.get_all_v().get(9))  # remove node without neighbors
     self.assertEqual(8, g0.v_size())
     self.assertEqual(2, g0.e_size())
     self.assertEqual(18, g0.get_mc())
Exemple #18
0
 def test_get(self):
     graph = DiGraph()
     graph.add_node(1, (1, 2, 3))  # add node check
     graph.add_node(2, (2, 3, 4))
     graph.add_node(3, (5, 4, 6))
     graph.add_node(4, (3, 4, 6))
     graph.add_edge(1, 2, 3)
     graph.add_edge(2, 3, 3)
     graph.add_edge(3, 4, 3)
     graph.add_edge(4, 1, 3)
     self.assertTrue(len(graph.get_all_v()) == 4)
Exemple #19
0
 def test_remove_edge(self):
     graph = DiGraph()
     for i in range(5):
         graph.add_node(i)
     weight_dict = {"0": 3.4, "1": 3.5, "2": 5.4, "3": 3.1, "4": 4.5}
     conn_dict = {"0": 1, "1": 2, "2": 3, "3": 4, "4": 0}
     remove_dict = {
         "0": False,
         "1": True,
         "2": False,
         "3": True,
         "4": False
     }
     for k in graph.get_all_v().keys():
         graph.add_edge(k, conn_dict[str(k)], weight_dict[str(k)])
     for k in range(0, 5, 2):
         graph.remove_edge(k, conn_dict[str(k)])
     for k in graph.get_all_v().keys():
         edge_dict = graph.all_out_edges_of_node(k)
         ans = edge_dict != {}
         self.assertEqual(ans, remove_dict[str(k)])
Exemple #20
0
 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())
Exemple #21
0
    def test_get_all_v(self):
        graph = DiGraph()
        for i in range(5):
            graph.add_node(i)
        graph.add_edge(0, 1, 1.2)
        graph.add_edge(1, 2, 1.2)
        graph.add_edge(2, 3, 1.2)
        graph.add_edge(3, 4, 1.2)

        n = graph.getNode(0)
        c = graph.get_all_v()
        z = c.keys()
        self.assertTrue(z.__contains__(n.getKey()))
        c.pop(n.getKey())
        self.assertFalse(z.__contains__(n.getKey()))
Exemple #22
0
 def test_edge_size(self):
     graph = DiGraph()
     for i in range(5):
         graph.add_node(i)
     weight_dict = {"0": 3.4, "1": 3.5, "2": 5.4, "3": 3.1, "4": 4.5}
     conn_dict = {"0": 1, "1": 2, "2": 3, "3": 4, "4": 0}
     for k in graph.get_all_v().keys():
         graph.add_edge(k, conn_dict[str(k)], weight_dict[str(k)])
     self.assertEqual(graph.e_size(), 5)
     graph.add_edge(0, 1, 3.5)
     self.assertEqual(graph.e_size(), 5)
     for k in range(0, 5, 2):
         graph.remove_edge(k, conn_dict[str(k)])
     self.assertEqual(graph.e_size(), 2)
     graph.remove_edge(0, 1)
     self.assertEqual(graph.e_size(), 2)
Exemple #23
0
    def test_get_all_v(self):
        graph = DiGraph()
        tuple0 = (0, 30, 2)
        tuple1 = (50, 50, 50)
        node0 = NodeData(0, tuple0)  # node: key=0 tuple=(0, 30, 2)
        node1 = NodeData(2, tuple0)  # node: key=2 tuple=(0, 30, 2)
        node2 = NodeData(10, tuple1)  # node: key=10 tuple=(50, 50, 50)

        graph.add_node(node0.get_key(), tuple0)
        graph.add_node(node1.get_key(), tuple0)
        graph.add_node(node2.get_key(), tuple1)

        nodes = [node0, node1, node2]

        for node in nodes:
            self.assertIn(node, graph.get_all_v().values())
Exemple #24
0
 def test_remove_node(self):
     graph = DiGraph()
     self.assertTrue(graph.add_node(1), (345.11, 7.74, 0))
     self.assertTrue(graph.add_node(0, (345.11, 7.74, 0)))
     graph1 = DiGraph()
     self.assertTrue(graph1.add_node(1), (345.11, 7.74, 0))
     self.assertTrue(graph1.add_node(0, (345.11, 7.74, 0)))
     self.assertEqual(len(graph.get_all_v()), len(graph1.get_all_v()))
     graph.add_edge(2, 6, 0)
     self.assertNotEqual(graph.get_all_v(), graph1.get_all_v())
     graph1.add_edge(2, 6, 0)
     self.assertEqual(graph.get_all_v(), graph1.get_all_v())
     self.assertEqual(graph, graph1)
     graph1.add_edge(6, 2, 0.9)
     self.assertNotEqual(graph1, graph)
    def test_remove_node(self):
        graph = DiGraph()
        self.assertTrue(graph.add_node(0,(22.22,31.53,0.0)))
        self.assertTrue(graph.add_node(1),(22.22,31.53,0.0))
        graph1 = DiGraph()
        self.assertTrue(graph1.add_node(0, (22.22, 31.53, 0.0)))
        self.assertTrue(graph1.add_node(1), (22.22, 31.53, 0.0))

        self.assertEqual(graph.get_all_v(),graph1.get_all_v())
        graph.add_edge(0,1,0)
        self.assertNotEqual(graph.get_all_v(),graph1.get_all_v())
        graph1.add_edge(0,1,0)
        self.assertEqual(graph.get_all_v(),graph1.get_all_v())
        self.assertEqual(graph,graph1)
        graph1.add_edge(1,0,0.9)
        self.assertNotEqual(graph1,graph)
 def test_add_node(self):
     g = DiGraph()
     assert True == g.add_node(0, (0, 0, 1))
     assert False == g.add_node(0, (0, 0, 1))
     assert True == g.add_node(1, (-2, 0, 1))
     assert True == g.add_node(2)
     assert 0 == g.get_all_v().get(0).getKey()
     assert 1 == g.get_all_v().get(1).getKey()
     assert 2 == g.get_all_v().get(2).getKey()
     assert (0, 0, 1) == g.get_all_v().get(0).getLocation()
     assert (-2, 0, 1) == g.get_all_v().get(1).getLocation()
     assert None == g.get_all_v().get(2).getLocation()
     assert 3 == g.v_size()
     g = self.graphCreator(20)
     assert 20 == g.v_size()
     g.add_node(18)
     assert 20 == g.v_size()
     g.add_node(22)
     assert 21 == g.v_size()
     assert 22 == g.get_all_v().get(22).getKey()
Exemple #27
0
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()
Exemple #28
0
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)
Exemple #29
0
class GraphAlgo(GraphAlgoInterface, ABC):
    def __init__(self, graph: DiGraph = None):
        if graph is not None:
            self.graph = graph
        else:
            self.graph = DiGraph()

    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:
        """
        Loads a graph from a json file.
        @param file_name: The path to the json file
        @returns True if the loading was successful, False o.w.
        """
        g = DiGraph()
        try:
            with open(file_name, "r") as f:
                details = json.load(f)
                nodes = details.get("Nodes")
                edges_out = details.get("Edges")
                for dic in nodes:
                    key = dic.get("id")
                    pos = dic.get("location")
                    g.add_node(key)
                    g.get_node(key).set_pos(pos)
                for dic in edges_out:
                    g.add_edge(dic.get("src"), dic.get("dest"), dic.get("w"))
                self.graph = g
            return True
        except Exception as e:
            print(e)
            return False

    def save_to_json(self, file_name: str) -> bool:
        """
        Saves the graph in JSON format to a file
        @param file_name: The path to the out file
        @return: True if the save was successful, False o.w.
        """
        try:
            with open(file_name, "w") as file:
                json.dump(self.graph,
                          default=lambda m: m.as_dict(),
                          indent=4,
                          fp=file)
                return True
        except IOError as e:
            return False

    def shortest_path(self, id1: int, id2: int) -> (float, list):
        """
        This function return the shortest path from src node to dest node
         using the helper function- Dijkstra to get the the previously node from each node that in the shortest path back from dest to src
        :param id1: The start node of the path
        :param id2: The end node of the path
        :return: tuple (distance, the path)
        """
        if id1 not in self.graph.get_all_v(
        ) or id2 not in self.graph.get_all_v():
            return -1, None
        parents = self.dijkstra(id1)
        dist = self.graph.get_node(id2).get_tag()
        if dist == sys.float_info.max:  # there is no way to get dest from src
            return -1, None
        if id1 == id2:
            path = [id1]
            return 0, path
        p = id2
        path = []
        while parents.get(
                p) is not None:  # there is a node before him in the path
            path.append(self.graph.get_node(p))
            p = parents.get(p)
        path.append(self.graph.get_node(p))  # add the last node (id1)
        path.reverse()
        return dist, path

    def connected_component(self, id1: int) -> list:
        """
        Finds the Strongly Connected Component(SCC) that node id1 is a part of.
        @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 []
        """
        if self.graph is None or id1 not in self.graph.get_all_v():
            return []
        nodes = self.graph.get_all_v().values()
        for node in nodes:
            node.arrive = False
        way_to = self.bfs(id1, True)
        way_from = self.bfs(id1, False)
        scc = {}
        for n in way_to.keys():
            if way_from.get(n) is not None:
                scc[n] = 1
        return list(scc.keys())

    def connected_components(self) -> List[list]:
        """
        Finds all the Strongly Connected Component(SCC) in the graph.
        @return: The list all SCC

        Notes:
        If the graph is None the function should return an empty list []
        """
        g = self.graph
        if g is None:
            return []
        scc = []
        # saw = []  # node that we already find their scc
        saw = {}
        for node in g.get_all_v().values():
            # if node not in saw:
            if saw.get(node) is None:
                temp_scc = self.connected_component(node.get_key())
                scc.append(temp_scc)
                for n in temp_scc:
                    saw[n] = 1
        return scc

    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
        """
        g = self.graph
        nodes = g.get_all_v().values()
        max_y = 0
        ax = plt.axes()
        ax.set_title('Graph', fontsize=14, fontweight='bold')
        ax.set_xlabel('x label')
        ax.set_ylabel('y label')
        for node in nodes:
            if node.get_pos() is None:
                x = 0
                y = 0
                count = 1
                ni_have_pos = False
                if len(node.get_edge_out()) != 0:
                    for ni in node.get_edge_out().keys():
                        n = g.get_node(ni)
                        if n.get_pos() is not None:
                            x += n.get_pos()[0]
                            y += n.get_pos()[1]
                            ++count
                            ni_have_pos = True
                    if ni_have_pos:
                        if count > 2:
                            x = x / count
                            y = y / count
                        else:
                            ni_have_pos = False
                elif len(node.get_edge_in()) != 0:
                    for ni in node.get_edge_in().keys():
                        n = g.get_node(ni)
                        if n.get_pos() is not None:
                            x += n.get_pos()[0]
                            y += n.get_pos()[1]
                            ++count
                            ni_have_pos = True
                    if ni_have_pos:
                        if count > 2:
                            x = x / count
                            y = y / count
                        else:
                            ni_have_pos = False
                if ni_have_pos is False:
                    x = random.randint(0, 100)
                    y = random.randint(0, 100)
                node.set_pos([x, y])
        for node in nodes:
            x = node.get_pos()[0]
            y = node.get_pos()[1]
            if y > max_y:
                max_y = y
            plt.plot(x, y, 'bo')
            ax.annotate(str(node.get_key()),
                        xy=(x, y),
                        xytext=(x - max_y / 100, y + max_y / 100),
                        color='green',
                        fontsize=12)
            plt.plot(x,
                     y,
                     color='blue',
                     markersize=7,
                     linewidth=7,
                     markerfacecolor='red',
                     markeredgecolor='pink',
                     markeredgewidth=1)
            for e in node.get_edge_out().keys():
                ni = g.get_node(e)
                x_ni = ni.get_pos()[0]
                y_ni = ni.get_pos()[1]
                # ax.arrow(x, y, x_ni-x, y_ni-y, head_width=0.1, head_length=0.3, fc='k', ec='k')
                # plt.arrow(x, y, x_ni-x, y_ni-y, width=0.1, visible=True, in_layout=True, head_width=0.5)
                plt.plot(x_ni,
                         y_ni,
                         color='blue',
                         markersize=7,
                         linewidth=7,
                         markerfacecolor='black',
                         markeredgecolor='pink',
                         markeredgewidth=1)
                connect = ConnectionPatch((x, y), (x_ni, y_ni),
                                          "data",
                                          "data",
                                          arrowstyle="-|>",
                                          linewidth=1.5,
                                          mutation_scale=20,
                                          fc="pink")
                ax.add_artist(connect)
        plt.show()

    # helper methods:

    def dijkstra(self, src_id: int) -> dict:
        """
        this function use in this class for help an other algorithms get the shortest path between two nodes, the shortest path length and decide whether the graph is connect or not
        by moving from the src node to its neighbors and set their tag (that save distance from src) in accordance to the weight between them,
        and then moving to each of their neighbors and set their tag accordance to the weight between them plus their "parents" tag cetera.
        at the same time Dijkstra saves the parent (previously node) for each node, for using in in other function.
        :param src_id: the id of the start node
        :return: dict of parents
        """
        self.restart()
        g = self.graph
        p_queue = queue.PriorityQueue()
        parents = {src_id: None}
        g.get_node(src_id).set_tag(0.0)  # the distance between node to himself
        p_queue.put(g.get_node(src_id))
        while not p_queue.empty():
            pred = p_queue.get()
            ni = g.all_out_edges_of_node(pred.get_key())
            for key, value in ni.items():  # add to the queue all the neighbors
                temp = g.get_node(key)
                if temp.get_info() == "not visited":
                    p_queue.put(temp)
            for key, value in ni.items(
            ):  # updating the right distance (in tag) in the neighbors
                temp = g.get_node(key)
                if temp.get_info() == "not visited":
                    dist = pred.get_tag() + g.get_edge(pred.get_key(),
                                                       temp.get_key())
                    if dist < temp.get_tag():
                        temp.set_tag(dist)
                        parents[temp.get_key()] = pred.get_key()
            pred.set_info("visited")
        return parents

    def bfs(self, src_id: int, regular: bool) -> dict:
        """
        this function use in this class for help an other algorithms get the Strongly Connected Component of the nodes.
        by moving from the src node to its neighbors and set its arrive field to True, and then moving to each of their
        neighbors and set arrive field to True and et cetera
        in this function there is no restart to arrive field, because we will use this information.
        The restart will be in the algorithms that use it.
        :param src_id:
        :return:    None
        """
        g = self.graph
        src_n = g.get_node(src_id)
        ans = {src_n: 1}
        nodes = g.get_all_v()
        for node in nodes.values():
            node.set_info("white")
        p_queue = queue.PriorityQueue()
        src_n.set_info("gray")
        src_n.arrive = True
        p_queue.put(src_n)
        while not p_queue.empty():
            pred = p_queue.get()
            if regular is True:
                edge = pred.get_edge_out()
            else:
                edge = pred.get_edge_in()
            for ni in edge.keys():
                temp = g.get_node(ni)
                if temp.get_info() != "black":
                    temp.set_info("gray")
                    temp.arrive = True
                    ans[temp] = 1
                    p_queue.put(temp)
            pred.set_info("black")
        return ans

    def restart(self) -> None:
        nodes = self.graph.get_all_v().values()
        my_iter = iter(nodes)
        while True:
            try:
                temp = next(my_iter)
                temp.set_tag(sys.float_info.max)
                temp.set_info("not visited")
            except StopIteration:
                break
Exemple #30
0
class GraphAlgo(GraphAlgoInterface):
    def __init__(self, graph=DiGraph()):

        self.__DWGraph = graph

    """
    This function return your graph.
    @reterns this graph.
    """

    def get_graph(self) -> GraphInterface:

        return self.__DWGraph

    """
    Load this json file (directed weighted graph). This function path of json file name on the computer. 
    The default path to this file is in the project folder. 
    we use json lib- Which allows us to extract the information from the json file that we need and read it 
    and create a new graph . and its data can be used to recreate the object in memory. The information we want to 
    load is: a dictionary of list of all edges and list of all nodes. the run time is: O(E*V)- E - edges and V-nodes. 
    we use json folder to get json file load.           
    @param file_name: The path to the json file
    @returns True if the loading was successful, False o.w.
    """

    def load_from_json(self, file_name: str) -> bool:

        try:
            with open(file_name, 'r') as JsonFile:

                self.__DWGraph = DiGraph()
                DataGraph = json.load(JsonFile)

                if 'Nodes' not in DataGraph or DataGraph[
                        "Nodes"] is None or DataGraph["Nodes"] is {}:
                    return False

                for node in DataGraph.get("Nodes"):
                    if "pos" in node:
                        pos = node.get("pos").split(",")
                        self.__DWGraph.add_node(
                            node.get("id"),
                            (float(pos[0]), float(pos[1]), float(pos[2])))
                    else:
                        self.__DWGraph.add_node(node.get("id"))
                if "Edges" in DataGraph:
                    if DataGraph["Edges"] is not None or DataGraph[
                            "Edges"] is not {}:
                        for edge in DataGraph.get("Edges"):
                            self.__DWGraph.add_edge(edge.get("src"),
                                                    edge.get("dest"),
                                                    edge.get("w"))
            return True

        except FileExistsError:
            return False

    """
    Saves this directed weighted graph to this json file name(file_name:str).
    This function path of json file name on the computer.
    The default path to this file is in the project folder(src).
    we use json lib- Which allows us to extract the information we need and write it into the json file. T
    he information we want to keep is: dictionary of list of all the edges and list of all the nodes.
    @param file_name: The path to the out file
    @return: True if the save was successful, False o.w.
    """

    def save_to_json(self, file_name: str) -> bool:

        try:
            with open(file_name, "w") as ToJsonFile:
                all_node = self.__DWGraph.get_all_v()
                if all_node is None or all_node is {}:
                    return False
                new_graph = {"Nodes": [], "Edges": []}
                for node in all_node:

                    if all_node[node].get_pos() is None:
                        new_graph["Nodes"].append({"id": node})
                    else:
                        new_graph["Nodes"].append({
                            "id":
                            node,
                            "pos":
                            str(all_node[node].get_pos()[0]) + "," +
                            str(all_node[node].get_pos()[1]) + "," +
                            str(all_node[node].get_pos()[2])
                        })

                    allEdge = self.__DWGraph.all_out_edges_of_node(node)
                    if allEdge is not None:
                        for edge in allEdge:
                            new_graph["Edges"].append({
                                "src": node,
                                "dest": edge,
                                "w": allEdge[edge]
                            })

                json.dump(new_graph, ToJsonFile)
                return True
        except FileExistsError:
            return False

    """
    This function returns tuple of the length of the shortest path between src to dest and the shortest pat list between src to dest - as an ordered List of nodes: source--> n1-->n2-->...destination. 
    In order to find the shortest path from source node to destination node we will use the algorithm of dijkstra.. if src==dest we return (inf, [id1])
    or if no path between the node -->  we return (inf, None).
    @param id1: The start node id
    @param id2: The end node id
    @return: The distance of the path, the path as a list
    """

    def shortest_path(self, id1: int, id2: int) -> (float, list):

        if id1 not in self.__DWGraph.get_all_v(
        ) or id2 not in self.__DWGraph.get_all_v():
            return None, []

        if id1 == id2:
            return 0, [id1]

        myDict = self.__dijkstra(id1)
        if id2 not in myDict:
            return math.inf, []

        parents = myDict.get(id2).get("parents")
        if parents == -1:
            return math.inf, None

        myPath = [id2]
        while parents != id1:
            myPath.append(parents)
            parents = myDict.get(parents).get("parents")

        myPath.append(id1)
        myPath.reverse()

        return myDict.get(id2).get("dist"), myPath

    """
         This algorithm makes it possible to go over a weighted directed graph And find the cheapest ways from the 
         source node to the rest of the graph nodes. 
         The weights in the graph symbolize distance. 
         The shortest route between two points means the route with the lowest amount of weights between the two vertices. 
         we use inner class that call nodeAlgo to save all the data that dijkstra algorithm need. 
         Ran time- O(E*log(V)) because we create PriorityQueue and compare the node by the minimum distance .
         @returns - dictionary of all the node with information about the chipsets paths from the source node 
         to all the node in the graph  
         for More info:
         https://en.wikipedia.org/wiki/Dijkstra's_algorithm
    """

    def __dijkstra(self, id_src) -> dict:
        pQueue = PriorityQueue()
        node_data = {id_src: {"dist": 0.0, "vis": False, "parents": -1}}
        pQueue.put((node_data.get(id_src).get("dist"), id_src))
        while not pQueue.empty():
            n = pQueue.get()[1]
            neighbor_w = self.__DWGraph.all_out_edges_of_node(n)

            if neighbor_w is not None:
                for neighbor in neighbor_w:

                    if neighbor not in node_data:
                        node_data.update({
                            neighbor: {
                                "dist": sys.maxsize,
                                "vis": False,
                                "pereants": -1
                            }
                        })

                    if not node_data.get(neighbor).get("vis"):
                        newDist = node_data.get(n).get(
                            "dist") + neighbor_w[neighbor]
                        if node_data.get(neighbor).get("dist") > newDist:
                            node_data.get(neighbor).update({"dist": newDist})
                            pQueue.put((node_data.get(neighbor).get("dist"),
                                        neighbor))
                            node_data.get(neighbor).update({"parents": n})

                    node_data.get(n).update({"vis": True})

        return node_data

    """
    This function checks if there is a Circular  Path from node id1 node to all the nodes With Dfs Algorithm- 
    this is an improved DFS called Tarjan Algorithm. after use DFS Algorithm we get list of list of all the phath in this component. 
    Tarjan_Algo dictionary - serves data Structure: stack ,lowlink ,count and st_trace. 
    run time O(E + V): E- the number of ribs, V- the number of nodes.
    @param id1: The node id
    @return: The list of nodes in the SCC
    """

    def connected_component(self, id1: int) -> list:

        if self.__DWGraph.get_all_v(
        ) is None or id1 not in self.__DWGraph.get_all_v():
            return []

        tarjan_dict = {
            "Nodes": {},
            "count": 0,
            "stack": [],
            "st_trace": [],
            "component": []
        }
        tarjan_dict.get("Nodes").update({id1: {"low_link": 0, "vis": -1}})

        tarjan_dict = self.__dfs(id1, tarjan_dict)

        ConnectedNodes = tarjan_dict.get("component")
        length = len(ConnectedNodes)

        if length == 1:
            return ConnectedNodes[0]

        else:
            for findId1 in ConnectedNodes:
                if id1 in findId1:
                    ConnectedNodes = findId1
                    break

        return ConnectedNodes

    """
    This function checks if there is a Path from each node to all the nodes With Dfs Algorithm- 
    this is an improved DFS called Tarjan Algorithm. 
    after use DFS Algorithm we get list of list of all the phath in this component  if the size of the list  
    equal to 1 So the graph is strongly connected and can be reached from any node to any other node. 
    Tarjan_Algo dictionary - serves data Structure: stack ,lowlink ,count and st_trace. 
    run time O(E + V): E- the number of ribs, V- the number of nodes.
    @return: The list all SCC
    """

    def connected_components(self) -> List[list]:

        if self.__DWGraph.get_all_v() is None:
            return []

        component = []
        tarjan_dict = {
            "Nodes": {},
            "count": 0,
            "stack": [],
            "st_trace": [],
            "component": []
        }
        for node in self.__DWGraph.get_all_v():

            if node not in tarjan_dict.get("Nodes"):
                tarjan_dict.get("Nodes").update(
                    {node: {
                        "low_link": 0,
                        "vis": -1
                    }})

            if tarjan_dict.get("Nodes").get(node)["vis"] == -1:
                tarjan_dict = self.__dfs(node, tarjan_dict)

            component = tarjan_dict.get("component")

        return component

    """
    This function draws the graph with matplotlib lib.
    """

    def plot_graph(self) -> None:

        nodes = self.__DWGraph.get_all_v()

        for key in nodes:

            if nodes[key].get_pos() is None:
                x_pos = random.uniform(0, len(nodes))
                y_pos = random.uniform(0, len(nodes))
                nodes[key].set_pos((x_pos, y_pos, 0.0))

            else:
                x_pos = nodes[key].get_pos()[0]
                y_pos = nodes[key].get_pos()[1]

            edge = self.__DWGraph.all_out_edges_of_node(key)

            print_graph.scatter(x_pos, y_pos, color='r', zorder=1)
            print_graph.text(x_pos + 0.0001,
                             y_pos + 0.0001,
                             str(key),
                             color='b',
                             zorder=5,
                             size=10)

            if edge is not None:

                for neighbor in edge:

                    if nodes[neighbor].get_pos() is None:

                        x_neighbor_pos = random.uniform(0, len(nodes))
                        y_neighbor_pos = random.uniform(0, len(nodes))
                        nodes[neighbor].set_pos(
                            (x_neighbor_pos, y_neighbor_pos, 0.0))

                    else:
                        x_neighbor_pos = nodes[neighbor].get_pos()[0]
                        y_neighbor_pos = nodes[neighbor].get_pos()[1]

                    print_graph.plot([x_pos, x_neighbor_pos],
                                     [y_pos, y_neighbor_pos],
                                     zorder=0,
                                     color='k')

                    # find all the point on this line
                    u = np.diff([x_pos, x_neighbor_pos])
                    v = np.diff([y_pos, y_neighbor_pos])
                    arrow_x = x_pos + u * 0.8
                    arrow_y = y_pos + v * 0.8
                    print_graph.quiver(
                        arrow_x,
                        arrow_y,
                        u,
                        v,
                        angles="xy",
                        headwidth=2.5,
                        zorder=0,
                        pivot="mid",
                        headlength=4,
                        color='k',
                    )

        print_graph.show()
        return None

    """
     his algorithm makes it possible to go over a weighted directed graph the node stack, 
     which starts out empty and stores the history of nodes explored but not yet committed to a strongly connected component.
     as nodes are not popped as the search returns up the tree; 
     they are only popped when an entire strongly connected component has been found. 
     The outermost loop searches each node that has not yet been visited, ensuring that nodes which are not reachable 
     from the first node are still eventually traversed. 
     finding all successors from the node v, and reporting all strongly connected components of that subgraph. 
     When each node finishes recursing, if its lowlink is still set to its index, 
     then it is the root node of a strongly connected component, formed by all of the nodes above it on the stack. 
     The algorithm pops the stack up to and including the current node, and presents all of these nodes as a strongly connected component. 
     Note that v.lowlink := min(v.lowlink, w.index) is the correct way to update v.lowlink if w is on stack. 
     Because w is on the stack already, (v, w) is a back-edge in the DFS tree and therefore w is not in the subtree of v. 
     Because v.lowlink takes into account nodes reachable only through the nodes in the subtree of v we must stop at w 
     and use w.index instead of w.lowlink.
     @returns - dictionary of all scc 

    """

    def __dfs(self, n, tarjan_dict) -> dict:

        parent = {}
        parent.update({n: n})
        tarjan_dict.get("stack").append(n)

        while len(tarjan_dict.get("stack")) != 0:

            n = tarjan_dict.get("stack")[len(tarjan_dict.get("stack")) - 1]
            if tarjan_dict.get("Nodes").get(n).get("vis") == -1:
                tarjan_dict.get("st_trace").append(n)

                tarjan_dict.get("Nodes").get(n).update(
                    {"low_link": tarjan_dict.get("count")})
                tarjan_dict.get("Nodes").get(n).update(
                    {"vis": tarjan_dict.get("count")})
                tarjan_dict.update({"count": tarjan_dict.get("count") + 1})

            flag = True
            edge_of_node = self.__DWGraph.all_out_edges_of_node(n)

            if edge_of_node is not None:

                for edge in edge_of_node:

                    if edge not in tarjan_dict.get("Nodes"):
                        tarjan_dict.get("Nodes").update(
                            {edge: {
                                "low_link": 0,
                                "vis": -1
                            }})

                    if tarjan_dict.get("Nodes").get(edge).get("vis") == -1:
                        flag = False
                        parent.update({edge: n})
                        tarjan_dict.get("stack").append(edge)
                        break

                    elif tarjan_dict.get("Nodes").get(edge).get(
                            "low_link") < tarjan_dict.get("Nodes").get(n).get(
                                "low_link"):
                        tarjan_dict.get("Nodes").get(n).update({
                            "low_link":
                            tarjan_dict.get("Nodes").get(edge).get("low_link")
                        })
            if flag:
                n = tarjan_dict.get("stack").pop()
                if tarjan_dict.get("Nodes").get(
                        n)["low_link"] < tarjan_dict.get("Nodes").get(
                            parent.get(n))["low_link"]:
                    tarjan_dict.get("Nodes").get(parent.get(n)).update({
                        "low_link":
                        tarjan_dict.get("Nodes").get(n).get("low_link")
                    })
                if tarjan_dict.get("Nodes").get(n).get(
                        "low_link") == tarjan_dict.get("Nodes").get(n).get(
                            "vis"):

                    tr_stack = tarjan_dict.get("st_trace")
                    component = []
                    while True:
                        my_node = tr_stack.pop()

                        component.append(my_node)
                        tarjan_dict.get("Nodes").get(my_node).update(
                            {"low_link": sys.maxsize})

                        if my_node == n:
                            break

                    tarjan_dict.get("component").append(component)

        return tarjan_dict