| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- import pytest
- import networkx as nx
- from networkx.utils import nodes_equal
- from .test_graph import BaseAttrGraphTester, BaseGraphTester
- from .test_graph import TestEdgeSubgraph as _TestGraphEdgeSubgraph
- from .test_graph import TestGraph as _TestGraph
- class BaseDiGraphTester(BaseGraphTester):
- def test_has_successor(self):
- G = self.K3
- assert G.has_successor(0, 1)
- assert not G.has_successor(0, -1)
- def test_successors(self):
- G = self.K3
- assert sorted(G.successors(0)) == [1, 2]
- with pytest.raises(nx.NetworkXError):
- G.successors(-1)
- def test_has_predecessor(self):
- G = self.K3
- assert G.has_predecessor(0, 1)
- assert not G.has_predecessor(0, -1)
- def test_predecessors(self):
- G = self.K3
- assert sorted(G.predecessors(0)) == [1, 2]
- with pytest.raises(nx.NetworkXError):
- G.predecessors(-1)
- def test_edges(self):
- G = self.K3
- assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
- assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
- assert sorted(G.edges([0, 1])) == [(0, 1), (0, 2), (1, 0), (1, 2)]
- with pytest.raises(nx.NetworkXError):
- G.edges(-1)
- def test_out_edges(self):
- G = self.K3
- assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
- assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
- with pytest.raises(nx.NetworkXError):
- G.out_edges(-1)
- def test_out_edges_dir(self):
- G = self.P3
- assert sorted(G.out_edges()) == [(0, 1), (1, 2)]
- assert sorted(G.out_edges(0)) == [(0, 1)]
- assert sorted(G.out_edges(2)) == []
- def test_out_edges_data(self):
- G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
- assert sorted(G.out_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
- assert sorted(G.out_edges(0, data=True)) == [(0, 1, {"data": 0})]
- assert sorted(G.out_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
- assert sorted(G.out_edges(0, data="data")) == [(0, 1, 0)]
- def test_in_edges_dir(self):
- G = self.P3
- assert sorted(G.in_edges()) == [(0, 1), (1, 2)]
- assert sorted(G.in_edges(0)) == []
- assert sorted(G.in_edges(2)) == [(1, 2)]
- def test_in_edges_data(self):
- G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
- assert sorted(G.in_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
- assert sorted(G.in_edges(1, data=True)) == [(0, 1, {"data": 0})]
- assert sorted(G.in_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
- assert sorted(G.in_edges(1, data="data")) == [(0, 1, 0)]
- def test_degree(self):
- G = self.K3
- assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)]
- assert dict(G.degree()) == {0: 4, 1: 4, 2: 4}
- assert G.degree(0) == 4
- assert list(G.degree(iter([0]))) == [(0, 4)] # run through iterator
- def test_in_degree(self):
- G = self.K3
- assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)]
- assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2}
- assert G.in_degree(0) == 2
- assert list(G.in_degree(iter([0]))) == [(0, 2)] # run through iterator
- def test_out_degree(self):
- G = self.K3
- assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)]
- assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2}
- assert G.out_degree(0) == 2
- assert list(G.out_degree(iter([0]))) == [(0, 2)]
- def test_size(self):
- G = self.K3
- assert G.size() == 6
- assert G.number_of_edges() == 6
- def test_to_undirected_reciprocal(self):
- G = self.Graph()
- G.add_edge(1, 2)
- assert G.to_undirected().has_edge(1, 2)
- assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
- G.add_edge(2, 1)
- assert G.to_undirected(reciprocal=True).has_edge(1, 2)
- def test_reverse_copy(self):
- G = nx.DiGraph([(0, 1), (1, 2)])
- R = G.reverse()
- assert sorted(R.edges()) == [(1, 0), (2, 1)]
- R.remove_edge(1, 0)
- assert sorted(R.edges()) == [(2, 1)]
- assert sorted(G.edges()) == [(0, 1), (1, 2)]
- def test_reverse_nocopy(self):
- G = nx.DiGraph([(0, 1), (1, 2)])
- R = G.reverse(copy=False)
- assert sorted(R.edges()) == [(1, 0), (2, 1)]
- with pytest.raises(nx.NetworkXError):
- R.remove_edge(1, 0)
- def test_reverse_hashable(self):
- class Foo:
- pass
- x = Foo()
- y = Foo()
- G = nx.DiGraph()
- G.add_edge(x, y)
- assert nodes_equal(G.nodes(), G.reverse().nodes())
- assert [(y, x)] == list(G.reverse().edges())
- def test_di_cache_reset(self):
- G = self.K3.copy()
- old_succ = G.succ
- assert id(G.succ) == id(old_succ)
- old_adj = G.adj
- assert id(G.adj) == id(old_adj)
- G._succ = {}
- assert id(G.succ) != id(old_succ)
- assert id(G.adj) != id(old_adj)
- old_pred = G.pred
- assert id(G.pred) == id(old_pred)
- G._pred = {}
- assert id(G.pred) != id(old_pred)
- def test_di_attributes_cached(self):
- G = self.K3.copy()
- assert id(G.in_edges) == id(G.in_edges)
- assert id(G.out_edges) == id(G.out_edges)
- assert id(G.in_degree) == id(G.in_degree)
- assert id(G.out_degree) == id(G.out_degree)
- assert id(G.succ) == id(G.succ)
- assert id(G.pred) == id(G.pred)
- class BaseAttrDiGraphTester(BaseDiGraphTester, BaseAttrGraphTester):
- def test_edges_data(self):
- G = self.K3
- all_edges = [
- (0, 1, {}),
- (0, 2, {}),
- (1, 0, {}),
- (1, 2, {}),
- (2, 0, {}),
- (2, 1, {}),
- ]
- assert sorted(G.edges(data=True)) == all_edges
- assert sorted(G.edges(0, data=True)) == all_edges[:2]
- assert sorted(G.edges([0, 1], data=True)) == all_edges[:4]
- with pytest.raises(nx.NetworkXError):
- G.edges(-1, True)
- def test_in_degree_weighted(self):
- G = self.K3.copy()
- G.add_edge(0, 1, weight=0.3, other=1.2)
- assert sorted(G.in_degree(weight="weight")) == [(0, 2), (1, 1.3), (2, 2)]
- assert dict(G.in_degree(weight="weight")) == {0: 2, 1: 1.3, 2: 2}
- assert G.in_degree(1, weight="weight") == 1.3
- assert sorted(G.in_degree(weight="other")) == [(0, 2), (1, 2.2), (2, 2)]
- assert dict(G.in_degree(weight="other")) == {0: 2, 1: 2.2, 2: 2}
- assert G.in_degree(1, weight="other") == 2.2
- assert list(G.in_degree(iter([1]), weight="other")) == [(1, 2.2)]
- def test_out_degree_weighted(self):
- G = self.K3.copy()
- G.add_edge(0, 1, weight=0.3, other=1.2)
- assert sorted(G.out_degree(weight="weight")) == [(0, 1.3), (1, 2), (2, 2)]
- assert dict(G.out_degree(weight="weight")) == {0: 1.3, 1: 2, 2: 2}
- assert G.out_degree(0, weight="weight") == 1.3
- assert sorted(G.out_degree(weight="other")) == [(0, 2.2), (1, 2), (2, 2)]
- assert dict(G.out_degree(weight="other")) == {0: 2.2, 1: 2, 2: 2}
- assert G.out_degree(0, weight="other") == 2.2
- assert list(G.out_degree(iter([0]), weight="other")) == [(0, 2.2)]
- class TestDiGraph(BaseAttrDiGraphTester, _TestGraph):
- """Tests specific to dict-of-dict-of-dict digraph data structure"""
- def setup_method(self):
- self.Graph = nx.DiGraph
- # build dict-of-dict-of-dict K3
- ed1, ed2, ed3, ed4, ed5, ed6 = ({}, {}, {}, {}, {}, {})
- self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}}
- self.k3edges = [(0, 1), (0, 2), (1, 2)]
- self.k3nodes = [0, 1, 2]
- self.K3 = self.Graph()
- self.K3._succ = self.k3adj # K3._adj is synced with K3._succ
- self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}}
- self.K3._node = {}
- self.K3._node[0] = {}
- self.K3._node[1] = {}
- self.K3._node[2] = {}
- ed1, ed2 = ({}, {})
- self.P3 = self.Graph()
- self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}}
- self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}}
- # P3._adj is synced with P3._succ
- self.P3._node = {}
- self.P3._node[0] = {}
- self.P3._node[1] = {}
- self.P3._node[2] = {}
- def test_data_input(self):
- G = self.Graph({1: [2], 2: [1]}, name="test")
- assert G.name == "test"
- assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
- assert sorted(G.succ.items()) == [(1, {2: {}}), (2, {1: {}})]
- assert sorted(G.pred.items()) == [(1, {2: {}}), (2, {1: {}})]
- def test_add_edge(self):
- G = self.Graph()
- G.add_edge(0, 1)
- assert G.adj == {0: {1: {}}, 1: {}}
- assert G.succ == {0: {1: {}}, 1: {}}
- assert G.pred == {0: {}, 1: {0: {}}}
- G = self.Graph()
- G.add_edge(*(0, 1))
- assert G.adj == {0: {1: {}}, 1: {}}
- assert G.succ == {0: {1: {}}, 1: {}}
- assert G.pred == {0: {}, 1: {0: {}}}
- with pytest.raises(ValueError, match="None cannot be a node"):
- G.add_edge(None, 3)
- def test_add_edges_from(self):
- G = self.Graph()
- G.add_edges_from([(0, 1), (0, 2, {"data": 3})], data=2)
- assert G.adj == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
- assert G.succ == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
- assert G.pred == {0: {}, 1: {0: {"data": 2}}, 2: {0: {"data": 3}}}
- with pytest.raises(nx.NetworkXError):
- G.add_edges_from([(0,)]) # too few in tuple
- with pytest.raises(nx.NetworkXError):
- G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
- with pytest.raises(TypeError):
- G.add_edges_from([0]) # not a tuple
- with pytest.raises(ValueError, match="None cannot be a node"):
- G.add_edges_from([(None, 3), (3, 2)])
- def test_remove_edge(self):
- G = self.K3.copy()
- G.remove_edge(0, 1)
- assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
- assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
- with pytest.raises(nx.NetworkXError):
- G.remove_edge(-1, 0)
- def test_remove_edges_from(self):
- G = self.K3.copy()
- G.remove_edges_from([(0, 1)])
- assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
- assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
- G.remove_edges_from([(0, 0)]) # silent fail
- def test_clear(self):
- G = self.K3
- G.graph["name"] = "K3"
- G.clear()
- assert list(G.nodes) == []
- assert G.succ == {}
- assert G.pred == {}
- assert G.graph == {}
- def test_clear_edges(self):
- G = self.K3
- G.graph["name"] = "K3"
- nodes = list(G.nodes)
- G.clear_edges()
- assert list(G.nodes) == nodes
- expected = {0: {}, 1: {}, 2: {}}
- assert G.succ == expected
- assert G.pred == expected
- assert list(G.edges) == []
- assert G.graph["name"] == "K3"
- class TestEdgeSubgraph(_TestGraphEdgeSubgraph):
- """Unit tests for the :meth:`DiGraph.edge_subgraph` method."""
- def setup_method(self):
- # Create a doubly-linked path graph on five nodes.
- G = nx.DiGraph(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.
- self.G = G
- self.H = G.edge_subgraph([(0, 1), (3, 4)])
- def test_pred_succ(self):
- """Test that nodes are added to predecessors and successors.
- For more information, see GitHub issue #2370.
- """
- G = nx.DiGraph()
- G.add_edge(0, 1)
- H = G.edge_subgraph([(0, 1)])
- assert list(H.predecessors(0)) == []
- assert list(H.successors(0)) == [1]
- assert list(H.predecessors(1)) == [0]
- assert list(H.successors(1)) == []
|