def setUp(self):
     self.graph = Graph()
     g = self.graph
     g.add_edge(1, 9)
     g.add_edge(9, 6)
     g.add_edge(6, 1)
     g.add_edge(1, 2)
     g.add_edge(2, 4)
     g.add_edge(4, 3)
     g.add_edge(3, 2)
     g.add_edge(2, 8)
     g.add_edge(1, 8)
     g.add_edge(8, 5)
     g.add_edge(5, 7)
     g.add_edge(7, 8)
     self.digraph = DiGraph()
     dig = self.digraph
     dig.add_edge(1, 2)
     dig.add_edge(2, 5)
     dig.add_edge(2, 3)
     dig.add_edge(5, 3)
     dig.add_edge(3, 5)
     dig.add_edge(5, 6)
     dig.add_edge(6, 3)
     dig.add_edge(3, 4)
     dig.add_edge(4, 2)
     dig.add_edge(3, 7)
     dig.add_edge(7, 8)
     dig.add_edge(8, 1)
    def setUp(self):
        self.nodes = [1, 'Sofia', 'Bourgas', 5.6555]
        self.edges = [(1, 'Sofia'), ('Sofia', 'Bourgas')]
        self.graph = DiGraph()
        for node in self.nodes:
            self.graph.add_node(node)

        for edge in self.edges:
            self.graph.add_edge(*edge)
def build_digraph(degree_sequence, nodes=None):
    ''' Generates directed graph of the given degree
        sequence (out, in). If nodes are provided, each
        node will have the corresponding data. '''

    if not is_valid_directed_degree_sequence(degree_sequence):
        raise InvalidDegreeSequence('Invalid degree sequence!')

    graph = DiGraph()
    degree_node = []

    if not nodes:
        nodes = count()

    for item in map(lambda x, z: [x[0], x[1], z], degree_sequence, nodes):
        degree_node.append(item)

    degree_node.sort(key=lambda x: x[1], reverse=True)
    degree_node.sort(key=lambda x: x[0], reverse=True)

    degree_node = deque(degree_node)

    while degree_node:
        out_degree, in_degree, node = degree_node.popleft()

        if in_degree == out_degree == 0:
            graph.add_node(node)
            continue

        for out_in_node in degree_node:
            if out_degree == 0:
                break
            if out_in_node[1]:
                out_in_node[1] -= 1
                out_degree -= 1
                graph.add_edge(node, out_in_node[2])

        if in_degree:
            degree_node.append([out_degree, in_degree, node])

    return graph
 def setUp(self):
     self.graph = Graph()
     self.graph.add_edge(1, 2)
     self.digraph = DiGraph()
     g = self.digraph
     g.add_edge(1, 3, w=3)
     g.add_edge(2, 3, w=5)
     g.add_edge(3, 5, w=11)
     g.add_edge(3, 4, w=8)
     g.add_edge(5, 6, w=12)
     g.add_edge(4, 7, w=16)
     g.add_edge(5, 7, w=14)
     g.add_edge(4, 6, w=18)
     g.add_edge(6, 8, w=21)
     g.add_edge(4, 7, w=16)
     g.add_edge(7, 8, w=16)
     g.add_edge(8, 10, w=7)
     g.add_edge(8, 9, w=5)
class MaxPathTest(unittest.TestCase):
    def setUp(self):
        self.graph = Graph()
        self.graph.add_edge(1, 2)
        self.digraph = DiGraph()
        g = self.digraph
        g.add_edge(1, 3, w=3)
        g.add_edge(2, 3, w=5)
        g.add_edge(3, 5, w=11)
        g.add_edge(3, 4, w=8)
        g.add_edge(5, 6, w=12)
        g.add_edge(4, 7, w=16)
        g.add_edge(5, 7, w=14)
        g.add_edge(4, 6, w=18)
        g.add_edge(6, 8, w=21)
        g.add_edge(4, 7, w=16)
        g.add_edge(7, 8, w=16)
        g.add_edge(8, 10, w=7)
        g.add_edge(8, 9, w=5)

    def test_max_path(self):
        pred, distance = max_path(self.digraph, weight_attribute='w')
        self.assertEqual(59, max(distance.values()))
        self.assertEqual(pred,
                         {3: 2, 4: 3, 5: 3, 6: 4,
                          7: 5, 8: 6, 9: 8, 10: 8})

    def test_max_path_graph(self):
        with self.assertRaises(NotDAG):
            max_path(self.graph)

    def test_max_path_digraph_with_cycle(self):
        self.digraph.add_edge(10, 8, w=4)
        with self.assertRaises(NotDAG):
            max_path(self.digraph)
        self.digraph.remove_edge(10, 8)

    def test_max_path_negative_edge(self):
        self.digraph.add_edge(1, 1000, w=-1)
        with self.assertRaises(NegativeEdgeWeight):
            max_path(self.digraph, weight_attribute='w')
        self.digraph.remove_edge(1, 1000)
    def setUp(self):
        self.positive_graph = Graph()
        pg = self.positive_graph
        pg.add_edge(1, 2, w=5)
        pg.add_edge(1, 3, w=29)
        pg.add_edge(1, 6, w=70)
        pg.add_edge(2, 3, w=10)
        pg.add_edge(2, 4, w=15)
        pg.add_edge(3, 4, w=51)
        pg.add_edge(4, 5, w=6)
        pg.add_edge(3, 6, w=10)

        self.positive_digraph = DiGraph()
        pdig = self.positive_digraph
        pdig.add_edge(1, 2, w=5)
        pdig.add_edge(1, 3, w=29)
        pdig.add_edge(1, 6, w=70)
        pdig.add_edge(2, 3, w=10)
        pdig.add_edge(2, 4, w=15)
        pdig.add_edge(3, 4, w=51)
        pdig.add_edge(4, 5, w=6)
        pdig.add_edge(3, 6, w=10)
 def test_bellman_ford_digraph_negative_edges(self):
     g = DiGraph()
     g.add_edge(1, 2, w=7)
     g.add_edge(1, 4, w=6)
     g.add_edge(4, 5, w=5)
     g.add_edge(5, 4, w=-2)
     g.add_edge(2, 3, w=9)
     g.add_edge(2, 5, w=-3)
     g.add_edge(4, 2, w=8)
     g.add_edge(4, 3, w=-4)
     g.add_edge(3, 1, w=7)
     g.add_edge(3, 5, w=7)
     self.assertEqual(shortest_paths_from(g, 1, weight_attribute='w'),
                      ({1: None, 2: 1, 3: 4, 4: 5, 5: 2},
                       {1: 0, 2: 7, 3: -2, 4: 2, 5: 4}))
class ShortestPathsTest(unittest.TestCase):
    def setUp(self):
        self.positive_graph = Graph()
        pg = self.positive_graph
        pg.add_edge(1, 2, w=5)
        pg.add_edge(1, 3, w=29)
        pg.add_edge(1, 6, w=70)
        pg.add_edge(2, 3, w=10)
        pg.add_edge(2, 4, w=15)
        pg.add_edge(3, 4, w=51)
        pg.add_edge(4, 5, w=6)
        pg.add_edge(3, 6, w=10)

        self.positive_digraph = DiGraph()
        pdig = self.positive_digraph
        pdig.add_edge(1, 2, w=5)
        pdig.add_edge(1, 3, w=29)
        pdig.add_edge(1, 6, w=70)
        pdig.add_edge(2, 3, w=10)
        pdig.add_edge(2, 4, w=15)
        pdig.add_edge(3, 4, w=51)
        pdig.add_edge(4, 5, w=6)
        pdig.add_edge(3, 6, w=10)

    def tearDown(self):
        del self.positive_digraph
        del self.positive_graph

    def test_unweighted_shortest_paths_graph(self):
        self.assertEqual(
            unweighted_shortest_paths(self.positive_graph, 1, 2),
            ({1: None, 2: 1, 3: 1, 4: 3, 5: 4, 6: 1},
             {1: 0, 2: 2, 3: 2, 4: 4, 5: 6, 6: 2}))

    def test_unweighted_shortest_paths_graph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            unweighted_shortest_paths(self.positive_graph, 999)

    def test_unweighted_shortest_paths_digraph(self):
        self.assertEqual(
            unweighted_shortest_paths(self.positive_digraph, 1),
            ({1: None, 2: 1, 3: 1, 4: 3, 5: 4, 6: 1},
             {1: 0, 2: 1, 3: 1, 4: 2, 5: 3, 6: 1}))

    def test_unweighted_shortest_paths_digraph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            unweighted_shortest_paths(self.positive_digraph, 999)

    def test_bellman_ford_graph(self):
        self.assertEqual(
            shortest_paths_from(self.positive_graph, 1, weight_attribute='w'),
            ({1: None, 2: 1, 3: 2, 4: 2, 5: 4, 6: 3},
             {1: 0, 2: 5, 3: 15, 4: 20, 5: 26, 6: 25}))

    def test_bellman_ford_graph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            shortest_paths_from(self.positive_graph, 999)

    def test_bellman_ford_graph_negative_edges(self):
        self.positive_graph.add_edge(1, 100, w=-1)
        with self.assertRaises(NegativeCycle):
            shortest_paths_from(self.positive_graph, 1, weight_attribute='w')
        self.positive_graph.remove_edge(1, 100)

    def test_bellman_ford_digraph(self):
        self.assertEqual(
            shortest_paths_from(
                self.positive_digraph, 1, weight_attribute='w'),
            ({1: None, 2: 1, 3: 2, 4: 2, 5: 4, 6: 3},
             {1: 0, 2: 5, 3: 15, 4: 20, 5: 26, 6: 25}))

    def test_bellman_ford_digraph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            shortest_paths_from(self.positive_digraph, 999)

    def test_bellman_ford_digraph_negative_edges(self):
        g = DiGraph()
        g.add_edge(1, 2, w=7)
        g.add_edge(1, 4, w=6)
        g.add_edge(4, 5, w=5)
        g.add_edge(5, 4, w=-2)
        g.add_edge(2, 3, w=9)
        g.add_edge(2, 5, w=-3)
        g.add_edge(4, 2, w=8)
        g.add_edge(4, 3, w=-4)
        g.add_edge(3, 1, w=7)
        g.add_edge(3, 5, w=7)
        self.assertEqual(shortest_paths_from(g, 1, weight_attribute='w'),
                         ({1: None, 2: 1, 3: 4, 4: 5, 5: 2},
                          {1: 0, 2: 7, 3: -2, 4: 2, 5: 4}))

    def test_bellman_ford_digraph_negative_cycle(self):
        self.positive_digraph.add_edge(2, 1, w=-6)
        with self.assertRaises(NegativeCycle):
            shortest_paths_from(
                self.positive_digraph, 1, weight_attribute='w')
        self.positive_digraph.remove_edge(2, 1)

    def test_dijkstra_graph(self):
        self.assertEqual(
            dijkstra(self.positive_graph, 1, weight_attribute='w'),
            ({1: None, 2: 1, 3: 2, 4: 2, 5: 4, 6: 3},
             {1: 0, 2: 5, 3: 15, 4: 20, 5: 26, 6: 25}))

    def test_dijkstra_graph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            dijkstra(self.positive_graph, 999)

    def test_dijkstra_digraph(self):
        self.assertEqual(
            dijkstra(self.positive_digraph, 1, weight_attribute='w'),
            ({1: None, 2: 1, 3: 2, 4: 2, 5: 4, 6: 3},
             {1: 0, 2: 5, 3: 15, 4: 20, 5: 26, 6: 25}))

    def test_dijkstra_digraph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            dijkstra(self.positive_digraph, 999)
class EulerianTest(unittest.TestCase):
    def setUp(self):
        self.graph = Graph()
        g = self.graph
        g.add_edge(1, 9)
        g.add_edge(9, 6)
        g.add_edge(6, 1)
        g.add_edge(1, 2)
        g.add_edge(2, 4)
        g.add_edge(4, 3)
        g.add_edge(3, 2)
        g.add_edge(2, 8)
        g.add_edge(1, 8)
        g.add_edge(8, 5)
        g.add_edge(5, 7)
        g.add_edge(7, 8)
        self.digraph = DiGraph()
        dig = self.digraph
        dig.add_edge(1, 2)
        dig.add_edge(2, 5)
        dig.add_edge(2, 3)
        dig.add_edge(5, 3)
        dig.add_edge(3, 5)
        dig.add_edge(5, 6)
        dig.add_edge(6, 3)
        dig.add_edge(3, 4)
        dig.add_edge(4, 2)
        dig.add_edge(3, 7)
        dig.add_edge(7, 8)
        dig.add_edge(8, 1)

    def tearDown(self):
        del self.digraph
        del self.graph

    def test_is_eulerain_graph(self):
        self.assertTrue(is_eulerian(self.graph))

    def test_is_eulerian_digraph(self):
        self.assertTrue(is_eulerian(self.digraph))

    def test_find_eulerian_cycle_graph(self):
        self.assertEqual(find_eulerian_cycle(self.graph, 1),
                         [1, 8, 5, 7, 8, 2, 3, 4, 2, 1, 9, 6, 1])

    def test_find_eulerian_cycle_graph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            find_eulerian_cycle(self.graph, 999)

    def test_find_eulerian_cycle_not_eulerian_graph(self):
        self.graph.add_edge(101, 102)
        self.assertEqual(find_eulerian_cycle(self.graph, 1), None)
        self.graph.remove_edge(101, 102)

    def test_find_eulerian_cycle_digraph(self):
        self.assertEqual(find_eulerian_cycle(self.digraph, 1),
                         [1, 2, 3, 4, 2, 5, 3, 5, 6, 3, 7, 8, 1])

    def test_find_eulerian_cycle_digraph_missing_node(self):
        with self.assertRaises(NodeNotFound):
            find_eulerian_cycle(self.digraph, 999)

    def test_find_eulerian_cycle_not_eulerian_digraph(self):
        self.digraph.add_edge(101, 102)
        self.assertEqual(find_eulerian_cycle(self.digraph, 1), None)
        self.digraph.remove_edge(101, 102)
class BasicDiGraphTest(unittest.TestCase):

    def setUp(self):
        self.nodes = [1, 'Sofia', 'Bourgas', 5.6555]
        self.edges = [(1, 'Sofia'), ('Sofia', 'Bourgas')]
        self.graph = DiGraph()
        for node in self.nodes:
            self.graph.add_node(node)

        for edge in self.edges:
            self.graph.add_edge(*edge)

    def tearDown(self):
        del self.nodes
        del self.graph

    def test_nodes_in_graph(self):
        for node in self.nodes:
            self.assertTrue(node in self.graph)
        self.assertFalse('NotANode' in self.graph)

    def test_edges_successors_predecessors(self):
        for (u, v) in self.edges:
            self.assertTrue(u in self.graph.get_predecessors(v))
            self.assertTrue(v in self.graph.get_successors(u))
            self.assertFalse(v in self.graph.get_predecessors(u))
            self.assertFalse(u in self.graph.get_successors(v))

    def test_has_edge(self):
        for (u, v) in self.edges:
            self.assertTrue(self.graph.has_edge(u, v))

    def test_remove_edge(self):
        u, v = 1, 'Bourgas'
        self.assertFalse(self.graph.has_edge(u, v))
        self.graph.add_edge(u, v)
        self.assertTrue(self.graph.has_edge(u, v))
        self.graph.remove_edge(u, v)
        self.assertFalse(self.graph.has_edge(u, v))

    def test_is_directed(self):
        self.assertTrue(self.graph.is_directed())

    def test_in_degree(self):
        self.assertEqual(self.graph.in_degree('Sofia'), 1)
        self.assertEqual(self.graph.in_degree(1), 0)

    def test_out_degree(self):
        self.assertEqual(self.graph.out_degree('Sofia'), 1)
        self.assertEqual(self.graph.out_degree('Bourgas'), 0)

    def test_degree(self):
        self.assertEqual(self.graph.degree('Sofia'), 2)
        self.assertEqual(self.graph.degree(5.6555), 0)

    def test_order(self):
        self.assertEqual(self.graph.order(), len(self.nodes))
        self.graph.add_node('AloneNode')
        self.assertEqual(self.graph.order(), len(self.nodes)+1)
        self.graph.remove_node('AloneNode')
        self.assertEqual(self.graph.order(), len(self.nodes))

    def test_size(self):
        self.assertEqual(self.graph.size(), len(self.edges))
        self.graph.add_edge(100, 100)
        self.assertEqual(self.graph.size(), len(self.edges) + 1)
        self.graph.remove_node(100)
        self.assertEqual(self.graph.size(), len(self.edges))