Exemple #1
0
 def test__len__(self) -> None:
     g = Graph([(1, 2), (2, 3), (3, 4)])
     tree: Tree[Vertex, Edge] = Tree(g[1])
     tree.add_edge(g.get_edge(1, 2))
     tree.add_edge(g.get_edge(2, 3))
     tree.add_edge(g.get_edge(3, 4))
     assert len(tree) == 4, "tree should contain 4 vertices"
Exemple #2
0
 def test_clear(self) -> None:
     g = Graph([(1, 2), (2, 3), (3, 4)])
     assert g.edge_count > 0, "graph should have edges"
     assert g.vertex_count > 0, "graph should have vertices"
     g.clear()
     assert g.edge_count == 0, "graph should not have edges after clear()"
     assert g.vertex_count == 0, "graph should not have vertices after clear()"
Exemple #3
0
 def test_vertices(self) -> None:
     g = Graph([(1, 2), (2, 3), (3, 4)])
     assert set(g.vertices()) == {
         g[1],
         g[2],
         g[3],
         g[4],
     }, "graph should have vertices 1, 2, 3, 4"
Exemple #4
0
 def test_edges_and_edge_count(self) -> None:
     g = Graph([(1, 2), (2, 1), (2, 3), (3, 4)])
     assert set(g.edges()) == {
         g.get_edge(1, 2),
         g.get_edge(2, 3),
         g.get_edge(3, 4),
     }, "edges should be (1, 2), (2, 3), (3, 4)"
     assert g.edge_count == 3, "graph should have 3 edges"
Exemple #5
0
    def test_exceptions(self) -> None:
        empty_g = Graph()
        with pytest.raises(exception.Unfeasible):
            components.connected_components(empty_g)

        g = Graph([(1, 2)])
        with pytest.raises(exception.GraphTypeNotSupported):
            components.strongly_connected_components(g)
Exemple #6
0
    def test_merge(self) -> None:
        g = Graph([(1, 2), (2, 3), (1, 4), (3, 4), (4, 5)])
        tree1: Tree[Vertex, Edge] = Tree(g[1])
        tree5: Tree[Vertex, Edge] = Tree(g[5])

        tree1.add_edge(g.get_edge(1, 4))
        tree1.add_edge(g.get_edge(4, 3))
        tree5.add_edge(g.get_edge(5, 4))
        tree1.merge(tree5)
        assert set(tree1.vertices()) == {tree1[1], tree1[3], tree1[4], tree1[5]}
Exemple #7
0
    def test_allows_self_loops(self) -> None:
        g = Graph()
        assert g.allows_self_loops(
        ), "graph should default to allowing self loops"
        g.add_edge(1, 1)  # graph should allow adding self loop

        g2 = Graph(allow_self_loops=False)
        assert not g2.allows_self_loops(
        ), "graph 2 should not allow self loops"
        with pytest.raises(exception.SelfLoopsNotAllowed):
            g2.add_edge(1, 1)
Exemple #8
0
 def test__iter__(self) -> None:
     g = Graph([(1, 2), (2, 3), (3, 4)])
     tree: Tree[Vertex, Edge] = Tree(g[1])
     tree.add_edge(g.get_edge(1, 2))
     tree.add_edge(g.get_edge(2, 3))
     tree.add_edge(g.get_edge(3, 4))
     count = sum(1 for _ in tree)
     assert count == 4, "tree should iterate over its 4 vertices"
     assert set([tree[1], tree[2], tree[3], tree[4]]) == set(
         tree
     ), "tree should iterate over its 4 vertices"
Exemple #9
0
 def test_add_vertex(self) -> None:
     g = Graph()
     g.add_vertex(1)
     g.add_vertex("2")
     g.add_vertex("v3", color="blue", mass=42)
     assert g.has_vertex(1), "graph should have vertex 1"
     assert g.has_vertex(2), "graph should have vertex 2"
     assert g.has_vertex("v3"), "graph should have vertex v3"
     assert g["v3"][
         "color"] == "blue", "vertex should have 'color' attribute set to 'blue'"
     assert g["v3"][
         "mass"] == 42, "vertex should have 'mass' attribute set to 42"
Exemple #10
0
    def test__getitem__setitem(self) -> None:
        g = Graph()
        v1: Vertex = g.add_vertex(1)
        pairs = [("1", "one"), (2, "two")]
        d1: VertexDict[str] = VertexDict(pairs)

        assert d1[
            v1] == "one", "Dict d1 getitem should work with Vertex object key"
        assert d1[1] == "one", "Dict d1 getitem should work with int key"
        assert d1["1"] == "one", "Dict d1 getitem should work with int key"
        assert d1[
            "2"] == "two", "Dict d1 should have item associated with key 2"
        d1[2] = "new value"
        assert d1[
            "2"] == "new value", 'Dict d1 should have "new value" for key 2'
Exemple #11
0
    def test_connected_components(self) -> None:
        g = Graph([(1, 2), (2, 3), (4, 5), (7, 7)])
        g.add_vertex(8)
        component_list: List[Component[Vertex, Edge]] = list(
            components.connected_components(g))
        assert len(component_list) == 4, "graph should have 4 components"
        edge_count = sum(
            len(list(component.edges())) for component in component_list)
        assert edge_count == 4, "components should contain a grand total of 4 edges"

        mg: MultiDiGraph = get_example_multidigraph()
        scc_list: List[Component[MultiDiVertex, MultiDiEdge]] = list(
            components.connected_components(mg))
        assert len(
            scc_list
        ) == 4, "multidigraph should have 4 strongly-connected components"
    def test_edmonds_undirected_graph(self) -> None:
        g = Graph([("s", "t", 10), ("s", "y", 5), ("t", "y", 2)])

        # Edmonds' algorithm does not work on undirected graphs.
        with pytest.raises(exception.GraphTypeNotSupported):
            for _ in directed.edmonds(g):
                pass
    def test_spanning_arborescence_undirected_graph(self) -> None:
        g = Graph([("s", "t", 10), ("s", "y", 5), ("t", "y", 2)])

        # Spanning arborescence is undefined for an undirected graph.
        with pytest.raises(exception.GraphTypeNotSupported):
            for _ in directed.spanning_arborescence(g):
                pass
Exemple #14
0
    def test_remove_edge(self) -> None:
        g = Graph([(1, 2), (2, 3), (3, 4)])
        assert g.edge_count == 3, "graph should have 3 edges"
        g.remove_edge(1, 2)
        assert g.edge_count == 2, "after edge removal, graph should have 2 edges"
        assert g.has_vertex(
            1), "isolated vertex 1 should not have been removed"

        g.remove_edge(2, 3, remove_semi_isolated_vertices=True)
        assert g.edge_count == 1, "after edge removal, graph should have 1 edge"
        assert not g.has_vertex(
            2
        ), "with `remove_semi_isolated_vertices` set to True, vertex 2 should have been removed"

        with pytest.raises(exception.EdgeNotFound):
            g.remove_edge(8, 9)
Exemple #15
0
    def test_component(self) -> None:
        g = Graph([(1, 2), (2, 3), (4, 5), (7, 7)])
        component_list: List[Component[Vertex, Edge]] = list(
            components.connected_components(g))
        c_123: Component[Vertex,
                         Edge] = [c for c in component_list if 1 in c][0]
        assert not c_123._edge_set, "without accessing edges, `_edge_set` should not be initialized"

        c_123.edges()
        assert c_123._edge_set, "after accessing edges, `_edge_set` should be initialized"

        c_45 = None
        c_77 = None
        for component in component_list:
            if (4, 5) in component:
                c_45 = component
            elif (7, 7) in component:
                c_77 = component

        assert c_45 is not None
        assert c_77 is not None
        assert (
            c_45._edge_set is not None
        ), "calling __contains__ should result in _edge_set initialization"
        assert (
            c_77._edge_set is not None
        ), "calling __contains__ should result in _edge_set initialization"
        assert g[
            7] in c_77, "vertex 7 should be in component containing edge (7, 7)"
Exemple #16
0
 def test_has_vertex(self) -> None:
     g = Graph()
     g.add_edge(1, 2)
     assert g.has_vertex(1), "vertex specified as int should be in graph"
     assert g.has_vertex("1"), "vertex specified as str should be in graph"
     v1 = g[1]
     assert g.has_vertex(
         v1), "vertex specified as object should be in graph"
     assert not g.has_vertex(3), "vertex 3 should not be in the graph"
Exemple #17
0
 def test_is_weighted(self) -> None:
     g = Graph()
     g.add_edge(1, 2)
     assert (
         not g.is_weighted()
     ), "graph without custom edge weights should not identify as weighted"
     g.add_edge(3, 4, weight=9.5)
     assert g.is_weighted(
     ), "graph with custom edge weights should identify as weighted"
Exemple #18
0
    def test_kruskal_optimum_forest_single_tree(self) -> None:
        g = Graph(test_edges)

        spanning_edges = set(undirected.kruskal_spanning_tree(g))
        spanning_tree = next(undirected.kruskal_optimum_forest(g))

        assert spanning_edges == set(spanning_tree.edges())
        assert spanning_tree.weight == 28, "Min spanning tree weight should be 28."
Exemple #19
0
    def test__contains__(self) -> None:
        g = Graph()
        g.add_edge(1, 2)
        assert g[1] in g, "vertex 1 should be in graph"
        assert 1 in g, "vertex specified as int should be in graph"
        assert "1" in g, "vertex specified as str should be in graph"
        assert 3 not in g, "vertex 3 should not be in graph"

        assert g.get_edge(1, 2) in g, "edge (1, 2) should be in graph"
        assert (1, 2) in g, "edge specified as tuple should be in graph"
        assert ("1", "2") in g, "edge specified as tuple should be in graph"
        assert (1, 3) not in g, "edge (1, 3) should not be in graph"

        with pytest.raises(TypeError):
            _ = 4.5 not in g  # type: ignore
        with pytest.raises(TypeError):
            _ = (1, 2, 3, 4) not in g  # type: ignore
Exemple #20
0
    def test__init__from_graph(self) -> None:
        g = Graph([(2, 1, 5.0, {"color": "red"}), (4, 3)])
        assert g.weight == 6.0, "graph should have weight 6.0"

        dg = DiGraph(g)
        assert dg.has_edge(
            2, 1), "digraph should have edge (2, 1) copied from graph"
        assert (dg.get_edge(2, 1)["color"] == "red"
                ), "edge (2, 1) should have 'color' attribute set to red"
        assert dg.get_edge(
            2, 1).weight == 5.0, "edge (2, 1) should have weight 5.0"
        assert dg.has_edge(
            4, 3), "graph should have edge (4, 3) copied from graph"
        assert dg.edge_count == 2, "graph should have two edges"
        assert dg.weight == 6.0, "graph should have weight 6.0"
        assert dg.get_edge(2, 1) is not g.get_edge(  # type: ignore
            2, 1), "digraph should have deep copies of edges and vertices"
Exemple #21
0
    def test_attr(self) -> None:
        g = Graph([(1, 2), (3, 4)], name="undirected graph", secret=42)

        assert g.attr["name"] == "undirected graph"
        assert g.attr[
            "secret"] == 42, "graph should have 'secret' attribute set to 42"
        with pytest.raises(KeyError):
            _ = g.attr["unknown_key"]
Exemple #22
0
    def test__contains__(self) -> None:
        g = Graph([(1, 2), (2, 3), (1, 4), (3, 4), (4, 5)])
        tree: Tree[Vertex, Edge] = Tree(g[1])
        assert g[1] in tree, "vertex 1 should be in tree"
        assert 1 in tree, "vertex specified as int should be in tree"
        assert "1" in tree, "vertex specified as str should be in tree"
        assert 3 not in tree, "vertex 3 should not be in tree"

        tree.add_edge(g.get_edge(1, 2))
        assert g.get_edge(1, 2) in tree
        assert (1, 2) in tree, "edge specified as tuple should be in tree"
        assert ("1", "2") in tree
        assert (1, 3) not in tree

        with pytest.raises(TypeError):
            _ = 4.5 not in g  # type: ignore
        with pytest.raises(TypeError):
            _ = (1, 2, 3, 4) not in g  # type: ignore
Exemple #23
0
    def test__init__from_graph(self) -> None:
        g0 = Graph([(1, 2, 5.0, {"color": "red"}), (3, 4)])

        g = MultiGraph(g0)
        assert g.has_edge(
            1, 2), "multigraph should have edge (1, 2) copied from graph"
        connection12 = g.get_edge(1, 2).connections()[0]
        assert (
            connection12["color"] == "red"
        ), "edge connection (1, 2) should have 'color' attribute set to red"
        assert g.get_edge(
            1, 2).weight == 5.0, "edge (1, 2) should have weight 5.0"
        assert g.has_edge(3,
                          4), "graph should have edge (3, 4) copied from graph"
        assert g.edge_count == 2, "graph should have two edges"
        assert g.weight == 6.0, "graph should have weight 6.0"
        assert g.get_edge(1, 2) is not g0.get_edge(  # type: ignore
            1, 2), "multigraph should have deep copies of edges and vertices"
Exemple #24
0
    def test_bfs_undirected_graph_with_self_loop_and_two_trees(self) -> None:
        g = Graph([(0, 0), (0, 1), (1, 2), (3, 4)])
        results: SearchResults[Vertex, Edge] = bfs(g)

        assert len(results.graph_search_trees()) == 2, "BFS should have discovered two BFS trees"
        assert len(results.vertices_preorder()) == 5, "BFS tree should have 5 vertices"
        assert (
            results.vertices_preorder() == results.vertices_postorder()
        ), "a BFS should yield vertices in same order for both preorder and postorder"
        assert len(results.back_edges()) == 1, "graph should have one self-loop back edge"
Exemple #25
0
 def test_vertex_count(self) -> None:
     g = Graph([(1, 2), (2, 3), (3, 4)])
     assert g.vertex_count == 4, "graph should have 4 vertices"
     g.add_vertex(5)
     assert g.vertex_count == 5, "graph should have 5 vertices"
     g.remove_vertex(5)
     assert g.vertex_count == 4, "graph should have 4 vertices"
    def test_dfs_undirected_cyclic_graph(self) -> None:
        g = Graph()
        g.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 3), (3, 4), (4, 5), (3, 5), (6, 7)])
        results: SearchResults[Vertex, Edge] = dfs(g, 0)
        tree: Tree[Vertex, Edge] = next(iter(results.graph_search_trees()))

        assert tree.root == 0, "DFS tree should be rooted at vertex 0"
        assert (
            len(results.graph_search_trees()) == 1
        ), "DFS search with source vertex should yield one DFS tree"
        assert len(tree) == 6, "DFS tree should have 6 vertices (excluding vertices 6 & 7)"
        assert (
            len(tree.edges()) == 5
        ), "DFS tree should have 5 edges, since for all trees |E| = |V| - 1"
        assert g[6] not in tree, "DFS tree should not contain vertex 6"
        assert not results.is_acyclic(), "graph should not be acyclic, since it contains 2 cycles"

        dfs_vertices = results.vertices_preorder()
        assert len(tree) == len(
            dfs_vertices
        ), "DFS vertices should match the DFS tree, since only one tree was searched"

        dfs_edges = results.edges_in_discovery_order()
        assert tree.edge_count == len(
            dfs_edges
        ), "DFS edges should match the DFS tree, since only one tree was searched"
        assert len(results.back_edges()) > 0, "tree should have back edges, since there are cycles"

        assert (
            not results.has_topological_ordering()
        ), "since graph contains cycles, there should be no topological ordering"

        first_edge: Edge = results.edges_in_discovery_order()[0]
        assert first_edge.vertex1 == 0, "first edge should have vertex1 of 0"
        assert first_edge.vertex2 == 1, "first edge should have vertex2 of 1"

        assert (
            not results.cross_edges() and not results.forward_edges()
        ), "using DFS in an undirected graph, every edge is either a tree edge or a back edge"
Exemple #27
0
    def test__getitem__(self) -> None:
        g = Graph([(1, 2), (2, 3), (1, 4), (3, 4), (4, 5)])
        tree: Tree[Vertex, Edge] = Tree(g[1])
        assert isinstance(tree[1], Vertex), "tree should have vertex 1"
        assert isinstance(tree["1"], Vertex), "tree should have vertex 1"
        assert isinstance(tree[(1, {})], Vertex), "tree should have vertex 1"
        assert isinstance(tree[1, {}], Vertex), "tree should have vertex 1"
        v1 = tree[1]
        assert isinstance(tree[v1], Vertex), "tree should have vertex 1"
        with pytest.raises(TypeError):
            _ = tree[2.0]  # type: ignore
        with pytest.raises(KeyError):
            _ = tree[3]

        tree.add_edge(g.get_edge(1, 2))
        assert isinstance(tree.get_edge(1, 2), Edge), "tree should have edge (1, 2)"
        assert isinstance(tree.get_edge("1", "2"), Edge), "tree should have edge (1, 2)"
        assert tree.has_edge(1, 2), "tree should have edge (1, 2)"
        with pytest.raises(KeyError):
            _ = g.get_edge(1.0, 2.0)  # type: ignore
        with pytest.raises(KeyError):
            _ = g.get_edge(1, 3)
Exemple #28
0
    def test_deepcopy(self) -> None:
        g = Graph([(1, 2, {"color": "blue"}), (3, 4)])
        g.add_vertex(42)
        g_copy = g.deepcopy()

        assert set(g.vertices()) == set(
            g_copy.vertices()), "graph copy should have same vertices"
        assert (
            g[1] is not g_copy[1]
        ), "graph copy vertex objects should be distinct from original graph"

        assert set(g.edges()) == set(
            g_copy.edges()), "graph copy should have same edges"
        assert g.get_edge(1, 2) is not g_copy.get_edge(
            1, 2
        ), "graph copy edge objects should be distinct from original graph"
        assert (
            g.get_edge(1, 2)._attr == g_copy.get_edge(1, 2)._attr
        ), "graph copy edge object `_attr` dictionary should contain logically equal contents"
        assert (
            g.get_edge(1, 2)._attr is not g_copy.get_edge(1, 2)._attr
        ), "graph copy edge object `_attr` dictionary should be distinct from original graph"
Exemple #29
0
    def test_contains(self) -> None:
        d: VertexDict[str] = VertexDict(**{"1": "one", "2": "two"})
        assert 1 in d
        assert "1" in d
        assert d.__contains__(2)

        g = Graph([(0, "six")])
        d2: VertexDict[str] = VertexDict()
        d2[g[0]] = "zero"
        d2[g["six"]] = "six"
        assert 0 in d2
        assert g[0] in d2
        assert "six" in d2
        assert g["six"] in d2
Exemple #30
0
    def test__getitem__(self) -> None:
        g = Graph()
        g.add_edge(1, 2)
        assert isinstance(g[1], Vertex), "graph should have vertex 1"
        assert isinstance(g["1"], Vertex), "graph should have vertex 1"
        assert isinstance(g[(1, {})], Vertex), "graph should have vertex 1"
        assert isinstance(g[1, {}], Vertex), "graph should have vertex 1"
        v1 = g[1]
        assert isinstance(g[v1], Vertex), "graph should have vertex 1"
        with pytest.raises(KeyError):
            _ = g.get_edge(1, 3)
        with pytest.raises(KeyError):
            _ = g[3]

        assert isinstance(g.get_edge(1, 2),
                          Edge), "graph should have edge (1, 2)"
        assert isinstance(g.get_edge("1", "2"),
                          Edge), "graph should have edge (1, 2)"
        _ = g.get_edge(1, 2)
        with pytest.raises(KeyError):
            _ = g.get_edge(1.0, 2.0)  # type: ignore
        with pytest.raises(KeyError):
            _ = g.get_edge(1, 3)