def test__find_scc__when_empty_graph__then_each_vertex_is_component():
     # given
     graph = DirectedSimpleGraph(range(4))
     # when
     result = list(find_scc(graph))
     # then
     assert_that(result).is_length(4)
     assert_that(result).contains_only({graph.get_vertex(0)}, {graph.get_vertex(1)},
                                       {graph.get_vertex(2)}, {graph.get_vertex(3)})
 def test__find_scc__when_single_component__then_all_vertices():
     # given
     graph = DirectedSimpleGraph(range(7))
     graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(1))
     graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(2))
     graph.add_edge_between(graph.get_vertex(2), graph.get_vertex(3))
     graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(4))
     graph.add_edge_between(graph.get_vertex(4), graph.get_vertex(5))
     graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(6))
     graph.add_edge_between(graph.get_vertex(6), graph.get_vertex(0))
     # when
     result = find_scc(graph)
     # then
     assert_that(list(result)).is_equal_to([set(graph.vertices)])
    def test__dfs_topological_sort__when_acyclic_graph__then_topological_order(
    ):
        # given
        graph = DirectedSimpleGraph(range(6))
        graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(4))
        graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(0))
        graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(4))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(1))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(0))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(1))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(4))
        # when
        result = dfs_topological_sort(graph)
        # then
        assert_that(result).is_instance_of(list)

        assert_that(result).is_in([
            graph.get_vertex(5),
            graph.get_vertex(3),
            graph.get_vertex(1),
            graph.get_vertex(0),
            graph.get_vertex(4),
            graph.get_vertex(2)
        ], [
            graph.get_vertex(3),
            graph.get_vertex(5),
            graph.get_vertex(1),
            graph.get_vertex(0),
            graph.get_vertex(2),
            graph.get_vertex(4)
        ], [
            graph.get_vertex(5),
            graph.get_vertex(3),
            graph.get_vertex(1),
            graph.get_vertex(0),
            graph.get_vertex(2),
            graph.get_vertex(4)
        ], [
            graph.get_vertex(3),
            graph.get_vertex(5),
            graph.get_vertex(1),
            graph.get_vertex(0),
            graph.get_vertex(4),
            graph.get_vertex(2)
        ])
    def test__inputs_topological_sort__when_cyclic_graph__then_directed_cyclic_graph_error(
    ):
        # given
        graph = DirectedSimpleGraph(range(6))
        graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(4))
        graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(0))
        graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(4))
        graph.add_edge_between(graph.get_vertex(2), graph.get_vertex(1))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(1))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(0))
        graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(1))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(2))
        graph.add_edge_between(graph.get_vertex(5), graph.get_vertex(4))

        # when
        def function(graph_):
            inputs_topological_sort(graph_)

        # then
        assert_that(function).raises(
            DirectedCyclicGraphError).when_called_with(graph)
 def test__find_scc__when_many_components_then_all_listed():
     # given
     graph = DirectedSimpleGraph(range(10))
     graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(4))
     graph.add_edge_between(graph.get_vertex(0), graph.get_vertex(5))
     graph.add_edge_between(graph.get_vertex(1), graph.get_vertex(0))
     graph.add_edge_between(graph.get_vertex(2), graph.get_vertex(3))
     graph.add_edge_between(graph.get_vertex(3), graph.get_vertex(1))
     graph.add_edge_between(graph.get_vertex(4), graph.get_vertex(1))
     graph.add_edge_between(graph.get_vertex(4), graph.get_vertex(3))
     graph.add_edge_between(graph.get_vertex(6), graph.get_vertex(5))
     graph.add_edge_between(graph.get_vertex(6), graph.get_vertex(9))
     graph.add_edge_between(graph.get_vertex(7), graph.get_vertex(4))
     graph.add_edge_between(graph.get_vertex(7), graph.get_vertex(6))
     graph.add_edge_between(graph.get_vertex(8), graph.get_vertex(3))
     graph.add_edge_between(graph.get_vertex(8), graph.get_vertex(7))
     graph.add_edge_between(graph.get_vertex(9), graph.get_vertex(8))
     # when
     result = list(find_scc(graph))
     # then
     assert_that(result).is_length(4)
     assert_that(result).contains_only(
         {graph.get_vertex(5)},
         {graph.get_vertex(2)},
         {graph.get_vertex(0), graph.get_vertex(1), graph.get_vertex(3), graph.get_vertex(4)},
         {graph.get_vertex(6), graph.get_vertex(7), graph.get_vertex(8), graph.get_vertex(9)})
class DirectedSimpleGraphTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.test_object = None

    def setUp(self):
        self.test_object = DirectedSimpleGraph(range(10))

    def test__properties_setitem_getitem__when_setting_property__then_property(
            self):
        # given
        vertex = Vertex(2)
        edge = self.test_object.add_edge_between(Vertex(0), Vertex(1))
        vertex_property = "x"
        edge_property = "y"
        # when
        self.test_object.properties[vertex] = vertex_property
        self.test_object.properties[edge] = edge_property

        result_vertex = self.test_object.properties[vertex]
        result_edge = self.test_object.properties[edge]
        # then
        assert_that(result_vertex).is_equal_to(vertex_property)
        assert_that(result_edge).is_equal_to(edge_property)

    def test__properties_getitem__when_no_property__then_null(self):
        # given
        vertex = Vertex(4)
        edge = self.test_object.add_edge_between(Vertex(6), Vertex(7))
        # when
        result_vertex = self.test_object.properties[vertex]
        result_edge = self.test_object.properties[edge]
        # then
        assert_that(result_vertex).is_none()
        assert_that(result_edge).is_none()

    def test__properties_getitem__when_not_existing__then_value_error(self):
        # when
        def function(item):
            return self.test_object.properties[item]

        # then
        assert_that(function).raises(ValueError).when_called_with(Vertex(14))
        assert_that(function).raises(ValueError).when_called_with(
            Edge(Vertex(2), Vertex(8)))
        assert_that(function).raises(ValueError).when_called_with(
            Edge(Vertex(0), Vertex(-1)))

    def test__properties_delitem__then_none(self):
        # given
        vertex = Vertex(4)
        edge = self.test_object.add_edge_between(Vertex(6), Vertex(7))
        self.test_object.properties[vertex] = "x"
        self.test_object.properties[edge] = "y"
        # when
        del self.test_object.properties[vertex]
        del self.test_object.properties[edge]
        # then
        assert_that(self.test_object.properties[vertex]).is_none()
        assert_that(self.test_object.properties[edge]).is_none()

    def test__vertices_count__then_number_of_vertices(self):
        # when
        result = self.test_object.vertices_count
        # then
        assert_that(result).is_equal_to(10)

    def test__edges_count__then_number_of_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(7), Vertex(7))
        self.test_object.add_edge_between(Vertex(1), Vertex(5))
        self.test_object.add_edge_between(Vertex(2), Vertex(4))
        self.test_object.add_edge_between(Vertex(8), Vertex(0))
        self.test_object.add_edge_between(Vertex(6), Vertex(3))
        self.test_object.add_edge_between(Vertex(3), Vertex(6))
        self.test_object.add_edge_between(Vertex(9), Vertex(3))
        # when
        result = self.test_object.edges_count
        # then
        assert_that(result).is_equal_to(7)

    def test__vertices__then_all_vertices(self):
        # when
        result = self.test_object.vertices
        # then
        assert_that(sorted(result)).is_equal_to([
            Vertex(0),
            Vertex(1),
            Vertex(2),
            Vertex(3),
            Vertex(4),
            Vertex(5),
            Vertex(6),
            Vertex(7),
            Vertex(8),
            Vertex(9)
        ])

    def test__edges__then_all_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(7), Vertex(7))
        self.test_object.add_edge_between(Vertex(1), Vertex(5))
        self.test_object.add_edge_between(Vertex(2), Vertex(4))
        self.test_object.add_edge_between(Vertex(8), Vertex(0))
        self.test_object.add_edge_between(Vertex(6), Vertex(3))
        self.test_object.add_edge_between(Vertex(3), Vertex(6))
        self.test_object.add_edge_between(Vertex(9), Vertex(3))
        # when
        result = self.test_object.edges
        # then
        assert_that(sorted(result)).is_equal_to([
            Edge(Vertex(1), Vertex(5)),
            Edge(Vertex(2), Vertex(4)),
            Edge(Vertex(3), Vertex(6)),
            Edge(Vertex(6), Vertex(3)),
            Edge(Vertex(7), Vertex(7)),
            Edge(Vertex(8), Vertex(0)),
            Edge(Vertex(9), Vertex(3))
        ])

    def test__get_vertex__when_exists__then_vertex(self):
        # given
        vertex_id = 6
        # when
        result = self.test_object.get_vertex(vertex_id)
        # then
        assert_that(result.id).is_equal_to(vertex_id)

    def test__get_vertex__when_not_exists__then_key_error(self):
        # when
        def function(id_):
            return self.test_object.get_vertex(id_)

        # then
        assert_that(function).raises(KeyError).when_called_with(14)

    def test__get_edge__when_in_direction__then_edge(self):
        # given
        source = Vertex(9)
        destination = Vertex(5)
        self.test_object.add_edge_between(source, destination)
        # when
        result = self.test_object.get_edge(source, destination)
        # then
        assert_that(result.source).is_equal_to(source)
        assert_that(result.destination).is_equal_to(destination)

    def test__get_edge__when_reversed_direction__then_key_error(self):
        # given
        source = Vertex(9)
        destination = Vertex(5)
        self.test_object.add_edge_between(source, destination)

        # then
        def function(source_, destination_):
            return self.test_object.get_edge(source_, destination_)

        # then
        assert_that(function).raises(KeyError).when_called_with(
            destination, source)

    def test__get_edge__when_not_exists__then_key_error(self):
        # when
        def function(source, destination):
            return self.test_object.get_edge(source, destination)

        # then
        assert_that(function).raises(KeyError).when_called_with(1, 2)

    def test__adjacent_edges__then_outgoing_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(1), Vertex(1))
        self.test_object.add_edge_between(Vertex(1), Vertex(3))
        self.test_object.add_edge_between(Vertex(1), Vertex(4))
        self.test_object.add_edge_between(Vertex(1), Vertex(7))
        self.test_object.add_edge_between(Vertex(1), Vertex(9))
        self.test_object.add_edge_between(Vertex(2), Vertex(1))
        self.test_object.add_edge_between(Vertex(6), Vertex(1))
        # when
        result = self.test_object.adjacent_edges(Vertex(1))
        # then
        assert_that(sorted(result)).is_equal_to([
            Edge(Vertex(1), Vertex(1)),
            Edge(Vertex(1), Vertex(3)),
            Edge(Vertex(1), Vertex(4)),
            Edge(Vertex(1), Vertex(7)),
            Edge(Vertex(1), Vertex(9))
        ])

    def test__neighbours__then_destination_vertices_of_outgoing_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(1), Vertex(1))
        self.test_object.add_edge_between(Vertex(1), Vertex(3))
        self.test_object.add_edge_between(Vertex(1), Vertex(4))
        self.test_object.add_edge_between(Vertex(1), Vertex(7))
        self.test_object.add_edge_between(Vertex(1), Vertex(9))
        self.test_object.add_edge_between(Vertex(2), Vertex(1))
        self.test_object.add_edge_between(Vertex(6), Vertex(1))
        # when
        result = self.test_object.neighbours(Vertex(1))
        # then
        assert_that(sorted(result)).is_equal_to(
            [Vertex(1), Vertex(3),
             Vertex(4), Vertex(7),
             Vertex(9)])

    def test__output_degree__then_number_of_outgoing_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(1), Vertex(1))
        self.test_object.add_edge_between(Vertex(1), Vertex(3))
        self.test_object.add_edge_between(Vertex(1), Vertex(4))
        self.test_object.add_edge_between(Vertex(1), Vertex(7))
        self.test_object.add_edge_between(Vertex(1), Vertex(9))
        self.test_object.add_edge_between(Vertex(2), Vertex(1))
        self.test_object.add_edge_between(Vertex(6), Vertex(1))
        # when
        result = self.test_object.output_degree(Vertex(1))
        # then
        assert_that(result).is_equal_to(5)

    def test__input_degree__then_number_of_incoming_edges(self):
        # given
        self.test_object.add_edge_between(Vertex(1), Vertex(1))
        self.test_object.add_edge_between(Vertex(3), Vertex(1))
        self.test_object.add_edge_between(Vertex(4), Vertex(1))
        self.test_object.add_edge_between(Vertex(7), Vertex(1))
        self.test_object.add_edge_between(Vertex(9), Vertex(1))
        self.test_object.add_edge_between(Vertex(1), Vertex(2))
        self.test_object.add_edge_between(Vertex(1), Vertex(6))
        # when
        result = self.test_object.input_degree(Vertex(1))
        # then
        assert_that(result).is_equal_to(5)

    def test__add_vertex__when_new_vertex__then_created_vertex(self):
        # given
        new_vertex_id = 13
        vertex_property = "qwerty"
        # when
        result = self.test_object.add_vertex(new_vertex_id, vertex_property)
        # then
        assert_that(result.id).is_equal_to(new_vertex_id)
        assert_that(self.test_object.vertices_count).is_equal_to(11)
        assert_that(list(self.test_object.neighbours(result))).is_empty()
        assert_that(
            self.test_object.properties[result]).is_equal_to(vertex_property)

    def test__add_vertex__when_existing_vertex__then_value_error(self):
        # given
        vertex = Vertex(6)
        vertex_property = "qwerty"
        self.test_object.properties[vertex] = vertex_property

        # when
        def function(vertex_):
            return self.test_object.add_vertex(vertex_, "abcdefg")

        # then
        assert_that(function).raises(ValueError).when_called_with(vertex)
        assert_that(self.test_object.vertices_count).is_equal_to(10)
        assert_that(
            self.test_object.properties[vertex]).is_equal_to(vertex_property)

    def test__add_edge_between__when_new_edge__then_created_edge(self):
        # given
        vertex1 = Vertex(1)
        vertex2 = Vertex(5)
        edge_property = "zxcvb"
        # when
        result = self.test_object.add_edge_between(vertex1, vertex2,
                                                   edge_property)
        self.test_object.add_edge_between(vertex1, vertex1)
        # then
        assert_that(result.source).is_equal_to(vertex1)
        assert_that(result.destination).is_equal_to(vertex2)
        assert_that(
            self.test_object.properties[result]).is_equal_to(edge_property)
        assert_that(sorted(self.test_object.neighbours(vertex1))).is_equal_to(
            [vertex1, vertex2])
        assert_that(list(self.test_object.neighbours(vertex2))).is_empty()

    def test__add_edge_between__when_duplicated_edge__then_value_error(self):
        # given
        source = Vertex(3)
        destination = Vertex(7)
        _ = self.test_object.add_edge_between(source, destination)

        # when
        def function(source_, destination_):
            return self.test_object.add_edge_between(source_, destination_)

        # then
        assert_that(function).raises(ValueError).when_called_with(
            source, destination)

    def test__reverse__then_all_edges_have_reversed_direction(self):
        # given
        vertex = Vertex(5)
        vertex_property = "123456"
        edge_property = "zxcvb"
        edge = self.test_object.add_edge_between(Vertex(1), Vertex(2))
        self.test_object.add_edge_between(Vertex(3), Vertex(5))
        self.test_object.add_edge_between(Vertex(4), Vertex(9))
        self.test_object.add_edge_between(Vertex(5), Vertex(4))
        self.test_object.add_edge_between(Vertex(5), Vertex(7))
        self.test_object.add_edge_between(Vertex(6), Vertex(2))
        self.test_object.add_edge_between(Vertex(6), Vertex(6))
        self.test_object.add_edge_between(Vertex(7), Vertex(8))
        self.test_object.add_edge_between(Vertex(9), Vertex(1))
        self.test_object.add_edge_between(Vertex(9), Vertex(6))
        self.test_object.properties[vertex] = vertex_property
        self.test_object.properties[edge] = edge_property
        # when
        self.test_object.reverse()
        # then
        assert_that(sorted(self.test_object.edges)).is_equal_to([
            Edge(Vertex(1), Vertex(9)),
            Edge(Vertex(2), Vertex(1)),
            Edge(Vertex(2), Vertex(6)),
            Edge(Vertex(4), Vertex(5)),
            Edge(Vertex(5), Vertex(3)),
            Edge(Vertex(6), Vertex(6)),
            Edge(Vertex(6), Vertex(9)),
            Edge(Vertex(7), Vertex(5)),
            Edge(Vertex(8), Vertex(7)),
            Edge(Vertex(9), Vertex(4))
        ])
        assert_that(
            self.test_object.properties[vertex]).is_equal_to(vertex_property)
        assert_that(self.test_object.properties[Vertex(9)]).is_none()
        assert_that(self.test_object.properties[self.test_object.get_edge(2, 1)]) \
            .is_equal_to(edge_property)
        assert_that(self.test_object.properties[self.test_object.get_edge(
            5, 3)]).is_none()

    def test__reversed_copy__then_new_graph_with_reversed_edges(self):
        # given
        vertex = Vertex(5)
        vertex_property = "123456"
        edge_property = "zxcvb"
        edge = self.test_object.add_edge_between(Vertex(1), Vertex(2))
        self.test_object.add_edge_between(Vertex(3), Vertex(5))
        self.test_object.add_edge_between(Vertex(4), Vertex(9))
        self.test_object.add_edge_between(Vertex(5), Vertex(4))
        self.test_object.add_edge_between(Vertex(5), Vertex(7))
        self.test_object.add_edge_between(Vertex(6), Vertex(2))
        self.test_object.add_edge_between(Vertex(6), Vertex(6))
        self.test_object.add_edge_between(Vertex(7), Vertex(8))
        self.test_object.add_edge_between(Vertex(9), Vertex(1))
        self.test_object.add_edge_between(Vertex(9), Vertex(6))
        self.test_object.properties[vertex] = vertex_property
        self.test_object.properties[edge] = edge_property
        # when
        result = self.test_object.reversed_copy()
        # then
        assert_that(sorted(result.vertices)).is_equal_to(
            sorted(self.test_object.vertices))
        assert_that(sorted(result.edges)).is_equal_to([
            Edge(Vertex(1), Vertex(9)),
            Edge(Vertex(2), Vertex(1)),
            Edge(Vertex(2), Vertex(6)),
            Edge(Vertex(4), Vertex(5)),
            Edge(Vertex(5), Vertex(3)),
            Edge(Vertex(6), Vertex(6)),
            Edge(Vertex(6), Vertex(9)),
            Edge(Vertex(7), Vertex(5)),
            Edge(Vertex(8), Vertex(7)),
            Edge(Vertex(9), Vertex(4))
        ])
        assert_that(result.properties[vertex]).is_equal_to(vertex_property)
        assert_that(result.properties[Vertex(9)]).is_none()
        assert_that(result.properties[result.get_edge(
            2, 1)]).is_equal_to(edge_property)
        assert_that(result.properties[result.get_edge(5, 3)]).is_none()
class PathsTest(unittest.TestCase):
    INF = Paths.INFINITY

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._directed_graph = None
        self._undirected_graph = None

    def setUp(self):
        self._directed_graph = DirectedSimpleGraph(range(10))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(0),
            self._directed_graph.get_vertex(1), self._Weight(4))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(4), self._Weight(7))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(7), self._Weight(12))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(2),
            self._directed_graph.get_vertex(4), self._Weight(6))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(2),
            self._directed_graph.get_vertex(6), self._Weight(8))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(0), self._Weight(3))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(7), self._Weight(5))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(5), self._Weight(1))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(3), self._Weight(10))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(5),
            self._directed_graph.get_vertex(6), self._Weight(4))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(5),
            self._directed_graph.get_vertex(8), self._Weight(2))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(6),
            self._directed_graph.get_vertex(5), self._Weight(7))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(7),
            self._directed_graph.get_vertex(5), self._Weight(2))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(7),
            self._directed_graph.get_vertex(8), self._Weight(6))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(9), self._Weight(10))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(9),
            self._directed_graph.get_vertex(6), self._Weight(3))

        self._undirected_graph = UndirectedSimpleGraph(range(10))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(1), self._Weight(4))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(4), self._Weight(7))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(7), self._Weight(12))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(2),
            self._undirected_graph.get_vertex(6), self._Weight(8))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(0), self._Weight(3))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(7), self._Weight(5))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(5), self._Weight(1))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(3), self._Weight(10))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(5),
            self._undirected_graph.get_vertex(8), self._Weight(2))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(7),
            self._undirected_graph.get_vertex(5), self._Weight(2))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(7),
            self._undirected_graph.get_vertex(8), self._Weight(6))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(9),
            self._undirected_graph.get_vertex(6), self._Weight(3))

    # region bellman_ford

    def test__bellman_ford__when_directed_graph__then_shortest_paths_lengths(
            self):
        # given
        distances = [20, 0, self.INF, 17, 7, 8, 12, 12, 10, 20]
        expected = _from_list(self._directed_graph, distances)
        # when
        result = bellman_ford(self._directed_graph,
                              self._directed_graph.get_vertex(1))
        # then
        assert_that(result).is_equal_to(expected)

    def test__bellman_ford__when_negative_edge__then_edge_included(self):
        # given
        distances = [8, 0, self.INF, 5, 7, 8, 12, 10, 10, 20]
        expected = _from_list(self._directed_graph, distances)

        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(3), self._Weight(-5))
        # when
        result = bellman_ford(self._directed_graph,
                              self._directed_graph.get_vertex(1))
        # then
        assert_that(result).is_equal_to(expected)

    def test__bellman_ford__when_undirected_graph__then_shortest_paths_lengths(
            self):
        # given
        distances = [4, 0, self.INF, 7, 7, 8, self.INF, 10, 10, self.INF]
        expected = _from_list(self._undirected_graph, distances)
        # when
        result = bellman_ford(self._undirected_graph.as_directed(),
                              self._undirected_graph.get_vertex(1))
        # then
        assert_that(result).is_equal_to(expected)

    def test__bellman_ford__when_negative_cycle__then_value_error(self):
        # given
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(3), self._Weight(-20))

        # when
        def function(graph):
            return bellman_ford(graph, graph.get_vertex(1))

        # then
        assert_that(function).raises(ValueError).when_called_with(
            self._directed_graph)

    # endregion
    # region dijkstra

    def test__dijkstra__when_directed_graph__then_shortest_paths_lengths(self):
        # given
        distances = [20, 0, self.INF, 17, 7, 8, 12, 12, 10, 20]
        expected = _from_list(self._directed_graph, distances)
        # when
        result = dijkstra(self._directed_graph,
                          self._directed_graph.get_vertex(1))
        # then
        assert_that(result).is_equal_to(expected)

    def test__dijkstra__when_undirected_graph__then_shortest_paths_lengths(
            self):
        # given
        distances = [4, 0, self.INF, 7, 7, 8, self.INF, 10, 10, self.INF]
        expected = _from_list(self._undirected_graph, distances)
        # when
        result = dijkstra(self._undirected_graph,
                          self._undirected_graph.get_vertex(1))
        # then
        assert_that(result).contains_only(*expected)
        assert_that(result).contains_entry(*({
            k: v
        } for k, v in expected.items()))

    def test__dijkstra__when_negative_edge__then_value_error(self):
        # given
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(2),
            self._directed_graph.get_vertex(1), self._Weight(-2))

        # when
        def function(graph):
            dijkstra(graph, graph.get_vertex(1))

        # then
        assert_that(function).raises(ValueError).when_called_with(
            self._directed_graph)

    # endregion
    # region floyd_warshall

    def test__floyd_warshall__when_directed_graph__then_shortest_paths_lengths(
            self):
        # given
        distances = [[0, 4, self.INF, 21, 11, 12, 16, 16, 14, 24],
                     [20, 0, self.INF, 17, 7, 8, 12, 12, 10, 20],
                     [19, 23, 0, 16, 6, 7, 8, 21, 9, 19],
                     [3, 7, self.INF, 0, 14, 7, 11, 5, 9, 19],
                     [13, 17, self.INF, 10, 0, 1, 5, 15, 3, 13],
                     [
                         self.INF, self.INF, self.INF, self.INF, self.INF, 0,
                         4, self.INF, 2, 12
                     ],
                     [
                         self.INF, self.INF, self.INF, self.INF, self.INF, 7,
                         0, self.INF, 9, 19
                     ],
                     [
                         self.INF, self.INF, self.INF, self.INF, self.INF, 2,
                         6, 0, 4, 14
                     ],
                     [
                         self.INF, self.INF, self.INF, self.INF, self.INF, 20,
                         13, self.INF, 0, 10
                     ],
                     [
                         self.INF, self.INF, self.INF, self.INF, self.INF, 10,
                         3, self.INF, 12, 0
                     ]]
        expected = _from_matrix(self._directed_graph, distances)
        # when
        result = floyd_warshall(self._directed_graph)
        # then
        assert_that(result).is_equal_to(expected)

    def test__floyd_warshall__when_negative_edge__then_edge_included(self):
        # given
        distances = [[0, 4, self.INF, 9, 11, 12, 16, 14, 14, 24],
                     [8, 0, self.INF, 5, 7, 8, 12, 10, 10, 20],
                     [7, 11, 0, 4, 6, 7, 8, 9, 9, 19],
                     [3, 7, self.INF, 0, 14, 7, 11, 5, 9, 19],
                     [1, 5, self.INF, -2, 0, 1, 5, 3, 3, 13],
                     [0, 4, self.INF, -3, 11, 0, 4, 2, 2, 12],
                     [7, 11, self.INF, 4, 18, 7, 0, 9, 9, 19],
                     [2, 6, self.INF, -1, 13, 2, 6, 0, 4, 14],
                     [-2, 2, self.INF, -5, 9, 2, 6, 0, 0, 10],
                     [10, 14, self.INF, 7, 21, 10, 3, 12, 12, 0]]
        expected = _from_matrix(self._directed_graph, distances)

        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(3), self._Weight(-5))
        # when
        result = floyd_warshall(self._directed_graph)
        # then
        assert_that(result).is_equal_to(expected)

    def test__floyd_warshall__when_undirected_graph__then_shortest_paths_lengths(
            self):
        # given
        distances = \
            [[0, 4, self.INF, 3, 11, 10, self.INF, 8, 12, self.INF],
             [4, 0, self.INF, 7, 7, 8, self.INF, 10, 10, self.INF],
             [self.INF, self.INF, 0, self.INF, self.INF, self.INF, 8, self.INF, self.INF, 11],
             [3, 7, self.INF, 0, 8, 7, self.INF, 5, 9, self.INF],
             [11, 7, self.INF, 8, 0, 1, self.INF, 3, 3, self.INF],
             [10, 8, self.INF, 7, 1, 0, self.INF, 2, 2, self.INF],
             [self.INF, self.INF, 8, self.INF, self.INF, self.INF, 0, self.INF, self.INF, 3],
             [8, 10, self.INF, 5, 3, 2, self.INF, 0, 4, self.INF],
             [12, 10, self.INF, 9, 3, 2, self.INF, 4, 0, self.INF],
             [self.INF, self.INF, 11, self.INF, self.INF, self.INF, 3, self.INF, self.INF, 0]]
        expected = _from_matrix(self._undirected_graph, distances)
        # when
        result = floyd_warshall(self._undirected_graph.as_directed())
        # then
        assert_that(result).is_equal_to(expected)

    # endregion

    class _Weight:
        def __init__(self, weight):
            self.weight = weight
예제 #8
0
class SearchingTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._directed_graph = None
        self._undirected_graph = None

    def setUp(self):
        self._directed_graph = DirectedSimpleGraph(range(10))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(0),
            self._directed_graph.get_vertex(1))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(3))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(7))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(4))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(0))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(5),
            self._directed_graph.get_vertex(4))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(5),
            self._directed_graph.get_vertex(8))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(6),
            self._directed_graph.get_vertex(2))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(6),
            self._directed_graph.get_vertex(9))
        self._directed_graph.add_edge_between(
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(5))

        self._undirected_graph = UndirectedSimpleGraph(range(10))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(1))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(4))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(3))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(7))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(2),
            self._undirected_graph.get_vertex(6))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(4))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(5))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(5),
            self._undirected_graph.get_vertex(8))
        self._undirected_graph.add_edge_between(
            self._undirected_graph.get_vertex(6),
            self._undirected_graph.get_vertex(9))

    # region bfs

    def test__bfs__when_undirected_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = bfs(self._undirected_graph, EmptyStrategy(),
                     [self._undirected_graph.get_vertex(0)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(5),
            self._undirected_graph.get_vertex(7),
            self._undirected_graph.get_vertex(8)
        ])

    def test__bfs__when_undirected_graph_and_many_roots__then_all_visited(
            self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = bfs(self._undirected_graph, strategy, [
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    def test__bfs__when_undirected_graph_and_no_roots__then_empty(self):
        # when
        result = bfs(self._undirected_graph, EmptyStrategy(), [])
        # then
        assert_that(list(result)).is_empty()

    def test__bfs__when_directed_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = bfs(self._directed_graph, EmptyStrategy(),
                     [self._directed_graph.get_vertex(1)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._directed_graph.get_vertex(0),
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(7)
        ])

    def test__bfs__when_directed_graph_and_many_roots__then_all_visited(self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = bfs(self._directed_graph, strategy, [
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._directed_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    # endregion
    # region dfs_iterative

    def test__dfs_iterative__when_undirected_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = dfs_iterative(self._undirected_graph, EmptyStrategy(),
                               [self._undirected_graph.get_vertex(0)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(5),
            self._undirected_graph.get_vertex(7),
            self._undirected_graph.get_vertex(8)
        ])

    def test__dfs_iterative__when_undirected_graph_and_many_roots__then_all_visited(
            self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = dfs_iterative(self._undirected_graph, strategy, [
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    def test__dfs_iterative__when_undirected_graph_and_no_roots__then_empty(
            self):
        # when
        result = dfs_iterative(self._undirected_graph, EmptyStrategy(), [])
        # then
        assert_that(list(result)).is_empty()

    def test__dfs_iterative__when_directed_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = dfs_iterative(self._directed_graph, EmptyStrategy(),
                               [self._directed_graph.get_vertex(1)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._directed_graph.get_vertex(0),
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(7)
        ])

    def test__dfs_iterative__when_directed_graph_and_many_roots__then_all_visited(
            self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = dfs_iterative(self._directed_graph, strategy, [
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._directed_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    # endregion
    # region dfs_recursive

    def test__dfs_recursive__when_undirected_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = dfs_recursive(self._undirected_graph, EmptyStrategy(),
                               [self._undirected_graph.get_vertex(0)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(1),
            self._undirected_graph.get_vertex(3),
            self._undirected_graph.get_vertex(4),
            self._undirected_graph.get_vertex(5),
            self._undirected_graph.get_vertex(7),
            self._undirected_graph.get_vertex(8)
        ])

    def test__dfs_recursive__when_undirected_graph_and_many_roots__then_all_visited(
            self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = dfs_recursive(self._undirected_graph, strategy, [
            self._undirected_graph.get_vertex(0),
            self._undirected_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    def test__dfs_recursive__when_undirected_graph_and_no_roots__then_empty(
            self):
        # when
        result = dfs_recursive(self._undirected_graph, EmptyStrategy(), [])
        # then
        assert_that(list(result)).is_empty()

    def test__dfs_recursive__when_directed_graph_and_single_root__then_visited_visited(
            self):
        # when
        result = dfs_recursive(self._directed_graph, EmptyStrategy(),
                               [self._directed_graph.get_vertex(1)])
        # then
        assert_that(sorted(result)).is_equal_to([
            self._directed_graph.get_vertex(0),
            self._directed_graph.get_vertex(1),
            self._directed_graph.get_vertex(3),
            self._directed_graph.get_vertex(4),
            self._directed_graph.get_vertex(7)
        ])

    def test__dfs_recursive__when_directed_graph_and_many_roots__then_all_visited(
            self):
        # given
        strategy = self._TestingStrategy()
        # when
        result = dfs_recursive(self._directed_graph, strategy, [
            self._directed_graph.get_vertex(8),
            self._directed_graph.get_vertex(6)
        ])
        # then
        assert_that(sorted(result)).is_equal_to(
            sorted(self._directed_graph.vertices))
        assert_that(sorted(strategy.entries)).is_equal_to(
            sorted(self._undirected_graph.vertices))
        assert_that(sorted(strategy.exits)).is_equal_to(
            sorted(self._undirected_graph.vertices))

    # endregion

    class _TestingStrategy(DFSStrategy):
        def __init__(self):
            self.entries = []
            self.exits = []

        def for_root(self, root):
            pass

        def on_entry(self, vertex):
            self.entries.append(vertex)

        def on_next_vertex(self, vertex, neighbour):
            pass

        def on_exit(self, vertex):
            self.exits.append(vertex)

        def on_edge_to_visited(self, vertex, neighbour):
            pass