342 lines
11 KiB
Python
342 lines
11 KiB
Python
|
import pytest
|
||
|
|
||
|
import networkx as nx
|
||
|
from networkx.testing import assert_edges_equal, assert_nodes_equal
|
||
|
|
||
|
# Note: SubGraph views are not tested here. They have their own testing file
|
||
|
|
||
|
|
||
|
class TestReverseView:
|
||
|
def setup(self):
|
||
|
self.G = nx.path_graph(9, create_using=nx.DiGraph())
|
||
|
self.rv = nx.reverse_view(self.G)
|
||
|
|
||
|
def test_pickle(self):
|
||
|
import pickle
|
||
|
|
||
|
rv = self.rv
|
||
|
prv = pickle.loads(pickle.dumps(rv, -1))
|
||
|
assert rv._node == prv._node
|
||
|
assert rv._adj == prv._adj
|
||
|
assert rv.graph == prv.graph
|
||
|
|
||
|
def test_contains(self):
|
||
|
assert (2, 3) in self.G.edges
|
||
|
assert (3, 2) not in self.G.edges
|
||
|
assert (2, 3) not in self.rv.edges
|
||
|
assert (3, 2) in self.rv.edges
|
||
|
|
||
|
def test_iter(self):
|
||
|
expected = sorted(tuple(reversed(e)) for e in self.G.edges)
|
||
|
assert sorted(self.rv.edges) == expected
|
||
|
|
||
|
def test_exceptions(self):
|
||
|
nxg = nx.graphviews
|
||
|
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, nx.Graph())
|
||
|
|
||
|
def test_subclass(self):
|
||
|
class MyGraph(nx.DiGraph):
|
||
|
def my_method(self):
|
||
|
return "me"
|
||
|
|
||
|
def to_directed_class(self):
|
||
|
return MyGraph()
|
||
|
|
||
|
M = MyGraph()
|
||
|
M.add_edge(1, 2)
|
||
|
RM = nx.reverse_view(M)
|
||
|
print("RM class", RM.__class__)
|
||
|
RMC = RM.copy()
|
||
|
print("RMC class", RMC.__class__)
|
||
|
print(RMC.edges)
|
||
|
assert RMC.has_edge(2, 1)
|
||
|
assert RMC.my_method() == "me"
|
||
|
|
||
|
|
||
|
class TestMultiReverseView:
|
||
|
def setup(self):
|
||
|
self.G = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||
|
self.G.add_edge(4, 5)
|
||
|
self.rv = nx.reverse_view(self.G)
|
||
|
|
||
|
def test_pickle(self):
|
||
|
import pickle
|
||
|
|
||
|
rv = self.rv
|
||
|
prv = pickle.loads(pickle.dumps(rv, -1))
|
||
|
assert rv._node == prv._node
|
||
|
assert rv._adj == prv._adj
|
||
|
assert rv.graph == prv.graph
|
||
|
|
||
|
def test_contains(self):
|
||
|
assert (2, 3, 0) in self.G.edges
|
||
|
assert (3, 2, 0) not in self.G.edges
|
||
|
assert (2, 3, 0) not in self.rv.edges
|
||
|
assert (3, 2, 0) in self.rv.edges
|
||
|
assert (5, 4, 1) in self.rv.edges
|
||
|
assert (4, 5, 1) not in self.rv.edges
|
||
|
|
||
|
def test_iter(self):
|
||
|
expected = sorted((v, u, k) for u, v, k in self.G.edges)
|
||
|
assert sorted(self.rv.edges) == expected
|
||
|
|
||
|
def test_exceptions(self):
|
||
|
nxg = nx.graphviews
|
||
|
MG = nx.MultiGraph(self.G)
|
||
|
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, MG)
|
||
|
|
||
|
|
||
|
class TestToDirected:
|
||
|
def setup(self):
|
||
|
self.G = nx.path_graph(9)
|
||
|
self.dv = nx.to_directed(self.G)
|
||
|
self.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||
|
self.Mdv = nx.to_directed(self.MG)
|
||
|
|
||
|
def test_directed(self):
|
||
|
assert not self.G.is_directed()
|
||
|
assert self.dv.is_directed()
|
||
|
|
||
|
def test_already_directed(self):
|
||
|
dd = nx.to_directed(self.dv)
|
||
|
Mdd = nx.to_directed(self.Mdv)
|
||
|
assert_edges_equal(dd.edges, self.dv.edges)
|
||
|
assert_edges_equal(Mdd.edges, self.Mdv.edges)
|
||
|
|
||
|
def test_pickle(self):
|
||
|
import pickle
|
||
|
|
||
|
dv = self.dv
|
||
|
pdv = pickle.loads(pickle.dumps(dv, -1))
|
||
|
assert dv._node == pdv._node
|
||
|
assert dv._succ == pdv._succ
|
||
|
assert dv._pred == pdv._pred
|
||
|
assert dv.graph == pdv.graph
|
||
|
|
||
|
def test_contains(self):
|
||
|
assert (2, 3) in self.G.edges
|
||
|
assert (3, 2) in self.G.edges
|
||
|
assert (2, 3) in self.dv.edges
|
||
|
assert (3, 2) in self.dv.edges
|
||
|
|
||
|
def test_iter(self):
|
||
|
revd = [tuple(reversed(e)) for e in self.G.edges]
|
||
|
expected = sorted(list(self.G.edges) + revd)
|
||
|
assert sorted(self.dv.edges) == expected
|
||
|
|
||
|
|
||
|
class TestToUndirected:
|
||
|
def setup(self):
|
||
|
self.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||
|
self.uv = nx.to_undirected(self.DG)
|
||
|
self.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||
|
self.Muv = nx.to_undirected(self.MDG)
|
||
|
|
||
|
def test_directed(self):
|
||
|
assert self.DG.is_directed()
|
||
|
assert not self.uv.is_directed()
|
||
|
|
||
|
def test_already_directed(self):
|
||
|
uu = nx.to_undirected(self.uv)
|
||
|
Muu = nx.to_undirected(self.Muv)
|
||
|
assert_edges_equal(uu.edges, self.uv.edges)
|
||
|
assert_edges_equal(Muu.edges, self.Muv.edges)
|
||
|
|
||
|
def test_pickle(self):
|
||
|
import pickle
|
||
|
|
||
|
uv = self.uv
|
||
|
puv = pickle.loads(pickle.dumps(uv, -1))
|
||
|
assert uv._node == puv._node
|
||
|
assert uv._adj == puv._adj
|
||
|
assert uv.graph == puv.graph
|
||
|
assert hasattr(uv, "_graph")
|
||
|
|
||
|
def test_contains(self):
|
||
|
assert (2, 3) in self.DG.edges
|
||
|
assert (3, 2) not in self.DG.edges
|
||
|
assert (2, 3) in self.uv.edges
|
||
|
assert (3, 2) in self.uv.edges
|
||
|
|
||
|
def test_iter(self):
|
||
|
expected = sorted(self.DG.edges)
|
||
|
assert sorted(self.uv.edges) == expected
|
||
|
|
||
|
|
||
|
class TestChainsOfViews:
|
||
|
@classmethod
|
||
|
def setup_class(cls):
|
||
|
cls.G = nx.path_graph(9)
|
||
|
cls.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||
|
cls.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||
|
cls.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||
|
cls.Gv = nx.to_undirected(cls.DG)
|
||
|
cls.DGv = nx.to_directed(cls.G)
|
||
|
cls.MGv = nx.to_undirected(cls.MDG)
|
||
|
cls.MDGv = nx.to_directed(cls.MG)
|
||
|
cls.Rv = cls.DG.reverse()
|
||
|
cls.MRv = cls.MDG.reverse()
|
||
|
cls.graphs = [
|
||
|
cls.G,
|
||
|
cls.DG,
|
||
|
cls.MG,
|
||
|
cls.MDG,
|
||
|
cls.Gv,
|
||
|
cls.DGv,
|
||
|
cls.MGv,
|
||
|
cls.MDGv,
|
||
|
cls.Rv,
|
||
|
cls.MRv,
|
||
|
]
|
||
|
for G in cls.graphs:
|
||
|
G.edges, G.nodes, G.degree
|
||
|
|
||
|
def test_pickle(self):
|
||
|
import pickle
|
||
|
|
||
|
for G in self.graphs:
|
||
|
H = pickle.loads(pickle.dumps(G, -1))
|
||
|
assert_edges_equal(H.edges, G.edges)
|
||
|
assert_nodes_equal(H.nodes, G.nodes)
|
||
|
|
||
|
def test_subgraph_of_subgraph(self):
|
||
|
SGv = nx.subgraph(self.G, range(3, 7))
|
||
|
SDGv = nx.subgraph(self.DG, range(3, 7))
|
||
|
SMGv = nx.subgraph(self.MG, range(3, 7))
|
||
|
SMDGv = nx.subgraph(self.MDG, range(3, 7))
|
||
|
for G in self.graphs + [SGv, SDGv, SMGv, SMDGv]:
|
||
|
SG = nx.induced_subgraph(G, [4, 5, 6])
|
||
|
assert list(SG) == [4, 5, 6]
|
||
|
SSG = SG.subgraph([6, 7])
|
||
|
assert list(SSG) == [6]
|
||
|
# subgraph-subgraph chain is short-cut in base class method
|
||
|
assert SSG._graph is G
|
||
|
|
||
|
def test_restricted_induced_subgraph_chains(self):
|
||
|
""" Test subgraph chains that both restrict and show nodes/edges.
|
||
|
|
||
|
A restricted_view subgraph should allow induced subgraphs using
|
||
|
G.subgraph that automagically without a chain (meaning the result
|
||
|
is a subgraph view of the original graph not a subgraph-of-subgraph.
|
||
|
"""
|
||
|
hide_nodes = [3, 4, 5]
|
||
|
hide_edges = [(6, 7)]
|
||
|
RG = nx.restricted_view(self.G, hide_nodes, hide_edges)
|
||
|
nodes = [4, 5, 6, 7, 8]
|
||
|
SG = nx.induced_subgraph(RG, nodes)
|
||
|
SSG = RG.subgraph(nodes)
|
||
|
assert RG._graph is self.G
|
||
|
assert SSG._graph is self.G
|
||
|
assert SG._graph is RG
|
||
|
assert_edges_equal(SG.edges, SSG.edges)
|
||
|
# should be same as morphing the graph
|
||
|
CG = self.G.copy()
|
||
|
CG.remove_nodes_from(hide_nodes)
|
||
|
CG.remove_edges_from(hide_edges)
|
||
|
assert_edges_equal(CG.edges(nodes), SSG.edges)
|
||
|
CG.remove_nodes_from([0, 1, 2, 3])
|
||
|
assert_edges_equal(CG.edges, SSG.edges)
|
||
|
# switch order: subgraph first, then restricted view
|
||
|
SSSG = self.G.subgraph(nodes)
|
||
|
RSG = nx.restricted_view(SSSG, hide_nodes, hide_edges)
|
||
|
assert RSG._graph is not self.G
|
||
|
assert_edges_equal(RSG.edges, CG.edges)
|
||
|
|
||
|
def test_subgraph_copy(self):
|
||
|
for origG in self.graphs:
|
||
|
G = nx.OrderedGraph(origG)
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
H = SG.copy()
|
||
|
assert type(G) == type(H)
|
||
|
|
||
|
def test_subgraph_todirected(self):
|
||
|
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||
|
SSG = SG.to_directed()
|
||
|
assert sorted(SSG) == [4, 5, 6]
|
||
|
assert sorted(SSG.edges) == [(4, 5), (5, 4), (5, 6), (6, 5)]
|
||
|
|
||
|
def test_subgraph_toundirected(self):
|
||
|
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||
|
SSG = SG.to_undirected()
|
||
|
assert list(SSG) == [4, 5, 6]
|
||
|
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||
|
|
||
|
def test_reverse_subgraph_toundirected(self):
|
||
|
G = self.DG.reverse(copy=False)
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
SSG = SG.to_undirected()
|
||
|
assert list(SSG) == [4, 5, 6]
|
||
|
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||
|
|
||
|
def test_reverse_reverse_copy(self):
|
||
|
G = self.DG.reverse(copy=False)
|
||
|
H = G.reverse(copy=True)
|
||
|
assert H.nodes == self.DG.nodes
|
||
|
assert H.edges == self.DG.edges
|
||
|
G = self.MDG.reverse(copy=False)
|
||
|
H = G.reverse(copy=True)
|
||
|
assert H.nodes == self.MDG.nodes
|
||
|
assert H.edges == self.MDG.edges
|
||
|
|
||
|
def test_subgraph_edgesubgraph_toundirected(self):
|
||
|
G = self.G.copy()
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
SSG = SG.edge_subgraph([(4, 5), (5, 4)])
|
||
|
USSG = SSG.to_undirected()
|
||
|
assert list(USSG) == [4, 5]
|
||
|
assert sorted(USSG.edges) == [(4, 5)]
|
||
|
|
||
|
def test_copy_subgraph(self):
|
||
|
G = self.G.copy()
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
CSG = SG.copy(as_view=True)
|
||
|
DCSG = SG.copy(as_view=False)
|
||
|
assert hasattr(CSG, "_graph") # is a view
|
||
|
assert not hasattr(DCSG, "_graph") # not a view
|
||
|
|
||
|
def test_copy_disubgraph(self):
|
||
|
G = self.DG.copy()
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
CSG = SG.copy(as_view=True)
|
||
|
DCSG = SG.copy(as_view=False)
|
||
|
assert hasattr(CSG, "_graph") # is a view
|
||
|
assert not hasattr(DCSG, "_graph") # not a view
|
||
|
|
||
|
def test_copy_multidisubgraph(self):
|
||
|
G = self.MDG.copy()
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
CSG = SG.copy(as_view=True)
|
||
|
DCSG = SG.copy(as_view=False)
|
||
|
assert hasattr(CSG, "_graph") # is a view
|
||
|
assert not hasattr(DCSG, "_graph") # not a view
|
||
|
|
||
|
def test_copy_multisubgraph(self):
|
||
|
G = self.MG.copy()
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
CSG = SG.copy(as_view=True)
|
||
|
DCSG = SG.copy(as_view=False)
|
||
|
assert hasattr(CSG, "_graph") # is a view
|
||
|
assert not hasattr(DCSG, "_graph") # not a view
|
||
|
|
||
|
def test_copy_of_view(self):
|
||
|
G = nx.OrderedMultiGraph(self.MGv)
|
||
|
assert G.__class__.__name__ == "OrderedMultiGraph"
|
||
|
G = G.copy(as_view=True)
|
||
|
assert G.__class__.__name__ == "OrderedMultiGraph"
|
||
|
|
||
|
def test_subclass(self):
|
||
|
class MyGraph(nx.DiGraph):
|
||
|
def my_method(self):
|
||
|
return "me"
|
||
|
|
||
|
def to_directed_class(self):
|
||
|
return MyGraph()
|
||
|
|
||
|
for origG in self.graphs:
|
||
|
G = MyGraph(origG)
|
||
|
SG = G.subgraph([4, 5, 6])
|
||
|
H = SG.copy()
|
||
|
assert SG.my_method() == "me"
|
||
|
assert H.my_method() == "me"
|
||
|
assert not 3 in H or 3 in SG
|