123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- import pytest
- import networkx as nx
- from networkx.utils import edges_equal
- class TestSubGraphView:
- gview = staticmethod(nx.graphviews.subgraph_view)
- graph = nx.Graph
- hide_edges_filter = staticmethod(nx.filters.hide_edges)
- show_edges_filter = staticmethod(nx.filters.show_edges)
- @classmethod
- def setup_class(cls):
- cls.G = nx.path_graph(9, create_using=cls.graph())
- cls.hide_edges_w_hide_nodes = {(3, 4), (4, 5), (5, 6)}
- def test_hidden_nodes(self):
- hide_nodes = [4, 5, 111]
- nodes_gone = nx.filters.hide_nodes(hide_nodes)
- gview = self.gview
- print(gview)
- G = gview(self.G, filter_node=nodes_gone)
- assert self.G.nodes - G.nodes == {4, 5}
- assert self.G.edges - G.edges == self.hide_edges_w_hide_nodes
- if G.is_directed():
- assert list(G[3]) == []
- assert list(G[2]) == [3]
- else:
- assert list(G[3]) == [2]
- assert set(G[2]) == {1, 3}
- pytest.raises(KeyError, G.__getitem__, 4)
- pytest.raises(KeyError, G.__getitem__, 112)
- pytest.raises(KeyError, G.__getitem__, 111)
- assert G.degree(3) == (3 if G.is_multigraph() else 1)
- assert G.size() == (7 if G.is_multigraph() else 5)
- def test_hidden_edges(self):
- hide_edges = [(2, 3), (8, 7), (222, 223)]
- edges_gone = self.hide_edges_filter(hide_edges)
- gview = self.gview
- G = gview(self.G, filter_edge=edges_gone)
- assert self.G.nodes == G.nodes
- if G.is_directed():
- assert self.G.edges - G.edges == {(2, 3)}
- assert list(G[2]) == []
- assert list(G.pred[3]) == []
- assert list(G.pred[2]) == [1]
- assert G.size() == 7
- else:
- assert self.G.edges - G.edges == {(2, 3), (7, 8)}
- assert list(G[2]) == [1]
- assert G.size() == 6
- assert list(G[3]) == [4]
- pytest.raises(KeyError, G.__getitem__, 221)
- pytest.raises(KeyError, G.__getitem__, 222)
- assert G.degree(3) == 1
- def test_shown_node(self):
- induced_subgraph = nx.filters.show_nodes([2, 3, 111])
- gview = self.gview
- G = gview(self.G, filter_node=induced_subgraph)
- assert set(G.nodes) == {2, 3}
- if G.is_directed():
- assert list(G[3]) == []
- else:
- assert list(G[3]) == [2]
- assert list(G[2]) == [3]
- pytest.raises(KeyError, G.__getitem__, 4)
- pytest.raises(KeyError, G.__getitem__, 112)
- pytest.raises(KeyError, G.__getitem__, 111)
- assert G.degree(3) == (3 if G.is_multigraph() else 1)
- assert G.size() == (3 if G.is_multigraph() else 1)
- def test_shown_edges(self):
- show_edges = [(2, 3), (8, 7), (222, 223)]
- edge_subgraph = self.show_edges_filter(show_edges)
- G = self.gview(self.G, filter_edge=edge_subgraph)
- assert self.G.nodes == G.nodes
- if G.is_directed():
- assert G.edges == {(2, 3)}
- assert list(G[3]) == []
- assert list(G[2]) == [3]
- assert list(G.pred[3]) == [2]
- assert list(G.pred[2]) == []
- assert G.size() == 1
- else:
- assert G.edges == {(2, 3), (7, 8)}
- assert list(G[3]) == [2]
- assert list(G[2]) == [3]
- assert G.size() == 2
- pytest.raises(KeyError, G.__getitem__, 221)
- pytest.raises(KeyError, G.__getitem__, 222)
- assert G.degree(3) == 1
- class TestSubDiGraphView(TestSubGraphView):
- gview = staticmethod(nx.graphviews.subgraph_view)
- graph = nx.DiGraph
- hide_edges_filter = staticmethod(nx.filters.hide_diedges)
- show_edges_filter = staticmethod(nx.filters.show_diedges)
- hide_edges = [(2, 3), (8, 7), (222, 223)]
- excluded = {(2, 3), (3, 4), (4, 5), (5, 6)}
- def test_inoutedges(self):
- edges_gone = self.hide_edges_filter(self.hide_edges)
- hide_nodes = [4, 5, 111]
- nodes_gone = nx.filters.hide_nodes(hide_nodes)
- G = self.gview(self.G, nodes_gone, edges_gone)
- assert self.G.in_edges - G.in_edges == self.excluded
- assert self.G.out_edges - G.out_edges == self.excluded
- def test_pred(self):
- edges_gone = self.hide_edges_filter(self.hide_edges)
- hide_nodes = [4, 5, 111]
- nodes_gone = nx.filters.hide_nodes(hide_nodes)
- G = self.gview(self.G, nodes_gone, edges_gone)
- assert list(G.pred[2]) == [1]
- assert list(G.pred[6]) == []
- def test_inout_degree(self):
- edges_gone = self.hide_edges_filter(self.hide_edges)
- hide_nodes = [4, 5, 111]
- nodes_gone = nx.filters.hide_nodes(hide_nodes)
- G = self.gview(self.G, nodes_gone, edges_gone)
- assert G.degree(2) == 1
- assert G.out_degree(2) == 0
- assert G.in_degree(2) == 1
- assert G.size() == 4
- # multigraph
- class TestMultiGraphView(TestSubGraphView):
- gview = staticmethod(nx.graphviews.subgraph_view)
- graph = nx.MultiGraph
- hide_edges_filter = staticmethod(nx.filters.hide_multiedges)
- show_edges_filter = staticmethod(nx.filters.show_multiedges)
- @classmethod
- def setup_class(cls):
- cls.G = nx.path_graph(9, create_using=cls.graph())
- multiedges = {(2, 3, 4), (2, 3, 5)}
- cls.G.add_edges_from(multiedges)
- cls.hide_edges_w_hide_nodes = {(3, 4, 0), (4, 5, 0), (5, 6, 0)}
- def test_hidden_edges(self):
- hide_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
- edges_gone = self.hide_edges_filter(hide_edges)
- G = self.gview(self.G, filter_edge=edges_gone)
- assert self.G.nodes == G.nodes
- if G.is_directed():
- assert self.G.edges - G.edges == {(2, 3, 4)}
- assert list(G[3]) == [4]
- assert list(G[2]) == [3]
- assert list(G.pred[3]) == [2] # only one 2 but two edges
- assert list(G.pred[2]) == [1]
- assert G.size() == 9
- else:
- assert self.G.edges - G.edges == {(2, 3, 4), (7, 8, 0)}
- assert list(G[3]) == [2, 4]
- assert list(G[2]) == [1, 3]
- assert G.size() == 8
- assert G.degree(3) == 3
- pytest.raises(KeyError, G.__getitem__, 221)
- pytest.raises(KeyError, G.__getitem__, 222)
- def test_shown_edges(self):
- show_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
- edge_subgraph = self.show_edges_filter(show_edges)
- G = self.gview(self.G, filter_edge=edge_subgraph)
- assert self.G.nodes == G.nodes
- if G.is_directed():
- assert G.edges == {(2, 3, 4)}
- assert list(G[3]) == []
- assert list(G.pred[3]) == [2]
- assert list(G.pred[2]) == []
- assert G.size() == 1
- else:
- assert G.edges == {(2, 3, 4), (7, 8, 0)}
- assert G.size() == 2
- assert list(G[3]) == [2]
- assert G.degree(3) == 1
- assert list(G[2]) == [3]
- pytest.raises(KeyError, G.__getitem__, 221)
- pytest.raises(KeyError, G.__getitem__, 222)
- # multidigraph
- class TestMultiDiGraphView(TestMultiGraphView, TestSubDiGraphView):
- gview = staticmethod(nx.graphviews.subgraph_view)
- graph = nx.MultiDiGraph
- hide_edges_filter = staticmethod(nx.filters.hide_multidiedges)
- show_edges_filter = staticmethod(nx.filters.show_multidiedges)
- hide_edges = [(2, 3, 0), (8, 7, 0), (222, 223, 0)]
- excluded = {(2, 3, 0), (3, 4, 0), (4, 5, 0), (5, 6, 0)}
- def test_inout_degree(self):
- edges_gone = self.hide_edges_filter(self.hide_edges)
- hide_nodes = [4, 5, 111]
- nodes_gone = nx.filters.hide_nodes(hide_nodes)
- G = self.gview(self.G, nodes_gone, edges_gone)
- assert G.degree(2) == 3
- assert G.out_degree(2) == 2
- assert G.in_degree(2) == 1
- assert G.size() == 6
- # induced_subgraph
- class TestInducedSubGraph:
- @classmethod
- def setup_class(cls):
- cls.K3 = G = nx.complete_graph(3)
- G.graph["foo"] = []
- G.nodes[0]["foo"] = []
- G.remove_edge(1, 2)
- ll = []
- G.add_edge(1, 2, foo=ll)
- G.add_edge(2, 1, foo=ll)
- def test_full_graph(self):
- G = self.K3
- H = nx.induced_subgraph(G, [0, 1, 2, 5])
- assert H.name == G.name
- self.graphs_equal(H, G)
- self.same_attrdict(H, G)
- def test_partial_subgraph(self):
- G = self.K3
- H = nx.induced_subgraph(G, 0)
- assert dict(H.adj) == {0: {}}
- assert dict(G.adj) != {0: {}}
- H = nx.induced_subgraph(G, [0, 1])
- assert dict(H.adj) == {0: {1: {}}, 1: {0: {}}}
- def same_attrdict(self, H, G):
- old_foo = H[1][2]["foo"]
- H.edges[1, 2]["foo"] = "baz"
- assert G.edges == H.edges
- H.edges[1, 2]["foo"] = old_foo
- assert G.edges == H.edges
- old_foo = H.nodes[0]["foo"]
- H.nodes[0]["foo"] = "baz"
- assert G.nodes == H.nodes
- H.nodes[0]["foo"] = old_foo
- assert G.nodes == H.nodes
- def graphs_equal(self, H, G):
- assert G._adj == H._adj
- assert G._node == H._node
- assert G.graph == H.graph
- assert G.name == H.name
- if not G.is_directed() and not H.is_directed():
- assert H._adj[1][2] is H._adj[2][1]
- assert G._adj[1][2] is G._adj[2][1]
- else: # at least one is directed
- if not G.is_directed():
- G._pred = G._adj
- G._succ = G._adj
- if not H.is_directed():
- H._pred = H._adj
- H._succ = H._adj
- assert G._pred == H._pred
- assert G._succ == H._succ
- assert H._succ[1][2] is H._pred[2][1]
- assert G._succ[1][2] is G._pred[2][1]
- # edge_subgraph
- class TestEdgeSubGraph:
- @classmethod
- def setup_class(cls):
- # Create a path graph on five nodes.
- cls.G = G = nx.path_graph(5)
- # Add some node, edge, and graph attributes.
- for i in range(5):
- G.nodes[i]["name"] = f"node{i}"
- G.edges[0, 1]["name"] = "edge01"
- G.edges[3, 4]["name"] = "edge34"
- G.graph["name"] = "graph"
- # Get the subgraph induced by the first and last edges.
- cls.H = nx.edge_subgraph(G, [(0, 1), (3, 4)])
- def test_correct_nodes(self):
- """Tests that the subgraph has the correct nodes."""
- assert [(0, "node0"), (1, "node1"), (3, "node3"), (4, "node4")] == sorted(
- self.H.nodes.data("name")
- )
- def test_correct_edges(self):
- """Tests that the subgraph has the correct edges."""
- assert edges_equal(
- [(0, 1, "edge01"), (3, 4, "edge34")], self.H.edges.data("name")
- )
- def test_add_node(self):
- """Tests that adding a node to the original graph does not
- affect the nodes of the subgraph.
- """
- self.G.add_node(5)
- assert [0, 1, 3, 4] == sorted(self.H.nodes)
- self.G.remove_node(5)
- def test_remove_node(self):
- """Tests that removing a node in the original graph
- removes the nodes of the subgraph.
- """
- self.G.remove_node(0)
- assert [1, 3, 4] == sorted(self.H.nodes)
- self.G.add_node(0, name="node0")
- self.G.add_edge(0, 1, name="edge01")
- def test_node_attr_dict(self):
- """Tests that the node attribute dictionary of the two graphs is
- the same object.
- """
- for v in self.H:
- assert self.G.nodes[v] == self.H.nodes[v]
- # Making a change to G should make a change in H and vice versa.
- self.G.nodes[0]["name"] = "foo"
- assert self.G.nodes[0] == self.H.nodes[0]
- self.H.nodes[1]["name"] = "bar"
- assert self.G.nodes[1] == self.H.nodes[1]
- # Revert the change, so tests pass with pytest-randomly
- self.G.nodes[0]["name"] = "node0"
- self.H.nodes[1]["name"] = "node1"
- def test_edge_attr_dict(self):
- """Tests that the edge attribute dictionary of the two graphs is
- the same object.
- """
- for u, v in self.H.edges():
- assert self.G.edges[u, v] == self.H.edges[u, v]
- # Making a change to G should make a change in H and vice versa.
- self.G.edges[0, 1]["name"] = "foo"
- assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
- self.H.edges[3, 4]["name"] = "bar"
- assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
- # Revert the change, so tests pass with pytest-randomly
- self.G.edges[0, 1]["name"] = "edge01"
- self.H.edges[3, 4]["name"] = "edge34"
- def test_graph_attr_dict(self):
- """Tests that the graph attribute dictionary of the two graphs
- is the same object.
- """
- assert self.G.graph is self.H.graph
- def test_readonly(self):
- """Tests that the subgraph cannot change the graph structure"""
- pytest.raises(nx.NetworkXError, self.H.add_node, 5)
- pytest.raises(nx.NetworkXError, self.H.remove_node, 0)
- pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6)
- pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1)
|