I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,75 @@
from itertools import groupby
import pytest
import networkx as nx
from networkx import graph_atlas, graph_atlas_g
from networkx.generators.atlas import NUM_GRAPHS
from networkx.utils import edges_equal, nodes_equal, pairwise
class TestAtlasGraph:
"""Unit tests for the :func:`~networkx.graph_atlas` function."""
def test_index_too_small(self):
with pytest.raises(ValueError):
graph_atlas(-1)
def test_index_too_large(self):
with pytest.raises(ValueError):
graph_atlas(NUM_GRAPHS)
def test_graph(self):
G = graph_atlas(6)
assert nodes_equal(G.nodes(), range(3))
assert edges_equal(G.edges(), [(0, 1), (0, 2)])
class TestAtlasGraphG:
"""Unit tests for the :func:`~networkx.graph_atlas_g` function."""
@classmethod
def setup_class(cls):
cls.GAG = graph_atlas_g()
def test_sizes(self):
G = self.GAG[0]
assert G.number_of_nodes() == 0
assert G.number_of_edges() == 0
G = self.GAG[7]
assert G.number_of_nodes() == 3
assert G.number_of_edges() == 3
def test_names(self):
for i, G in enumerate(self.GAG):
assert int(G.name[1:]) == i
def test_nondecreasing_nodes(self):
# check for nondecreasing number of nodes
for n1, n2 in pairwise(map(len, self.GAG)):
assert n2 <= n1 + 1
def test_nondecreasing_edges(self):
# check for nondecreasing number of edges (for fixed number of
# nodes)
for n, group in groupby(self.GAG, key=nx.number_of_nodes):
for m1, m2 in pairwise(map(nx.number_of_edges, group)):
assert m2 <= m1 + 1
def test_nondecreasing_degree_sequence(self):
# Check for lexicographically nondecreasing degree sequences
# (for fixed number of nodes and edges).
#
# There are three exceptions to this rule in the order given in
# the "Atlas of Graphs" book, so we need to manually exclude
# those.
exceptions = [("G55", "G56"), ("G1007", "G1008"), ("G1012", "G1013")]
for n, group in groupby(self.GAG, key=nx.number_of_nodes):
for m, group in groupby(group, key=nx.number_of_edges):
for G1, G2 in pairwise(group):
if (G1.name, G2.name) in exceptions:
continue
d1 = sorted(d for v, d in G1.degree())
d2 = sorted(d for v, d in G2.degree())
assert d1 <= d2

View File

@ -0,0 +1,640 @@
"""
====================
Generators - Classic
====================
Unit tests for various classic graph generators in generators/classic.py
"""
import itertools
import typing
import pytest
import networkx as nx
from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic
from networkx.utils import edges_equal, nodes_equal
is_isomorphic = graph_could_be_isomorphic
class TestGeneratorClassic:
def test_balanced_tree(self):
# balanced_tree(r,h) is a tree with (r**(h+1)-1)/(r-1) edges
for r, h in [(2, 2), (3, 3), (6, 2)]:
t = nx.balanced_tree(r, h)
order = t.order()
assert order == (r ** (h + 1) - 1) / (r - 1)
assert nx.is_connected(t)
assert t.size() == order - 1
dh = nx.degree_histogram(t)
assert dh[0] == 0 # no nodes of 0
assert dh[1] == r**h # nodes of degree 1 are leaves
assert dh[r] == 1 # root is degree r
assert dh[r + 1] == order - r**h - 1 # everyone else is degree r+1
assert len(dh) == r + 2
def test_balanced_tree_star(self):
# balanced_tree(r,1) is the r-star
t = nx.balanced_tree(r=2, h=1)
assert is_isomorphic(t, nx.star_graph(2))
t = nx.balanced_tree(r=5, h=1)
assert is_isomorphic(t, nx.star_graph(5))
t = nx.balanced_tree(r=10, h=1)
assert is_isomorphic(t, nx.star_graph(10))
def test_balanced_tree_path(self):
"""Tests that the balanced tree with branching factor one is the
path graph.
"""
# A tree of height four has five levels.
T = nx.balanced_tree(1, 4)
P = nx.path_graph(5)
assert is_isomorphic(T, P)
def test_full_rary_tree(self):
r = 2
n = 9
t = nx.full_rary_tree(r, n)
assert t.order() == n
assert nx.is_connected(t)
dh = nx.degree_histogram(t)
assert dh[0] == 0 # no nodes of 0
assert dh[1] == 5 # nodes of degree 1 are leaves
assert dh[r] == 1 # root is degree r
assert dh[r + 1] == 9 - 5 - 1 # everyone else is degree r+1
assert len(dh) == r + 2
def test_full_rary_tree_balanced(self):
t = nx.full_rary_tree(2, 15)
th = nx.balanced_tree(2, 3)
assert is_isomorphic(t, th)
def test_full_rary_tree_path(self):
t = nx.full_rary_tree(1, 10)
assert is_isomorphic(t, nx.path_graph(10))
def test_full_rary_tree_empty(self):
t = nx.full_rary_tree(0, 10)
assert is_isomorphic(t, nx.empty_graph(10))
t = nx.full_rary_tree(3, 0)
assert is_isomorphic(t, nx.empty_graph(0))
def test_full_rary_tree_3_20(self):
t = nx.full_rary_tree(3, 20)
assert t.order() == 20
def test_barbell_graph(self):
# number of nodes = 2*m1 + m2 (2 m1-complete graphs + m2-path + 2 edges)
# number of edges = 2*(nx.number_of_edges(m1-complete graph) + m2 + 1
m1 = 3
m2 = 5
b = nx.barbell_graph(m1, m2)
assert nx.number_of_nodes(b) == 2 * m1 + m2
assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1
m1 = 4
m2 = 10
b = nx.barbell_graph(m1, m2)
assert nx.number_of_nodes(b) == 2 * m1 + m2
assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1
m1 = 3
m2 = 20
b = nx.barbell_graph(m1, m2)
assert nx.number_of_nodes(b) == 2 * m1 + m2
assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1
# Raise NetworkXError if m1<2
m1 = 1
m2 = 20
pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2)
# Raise NetworkXError if m2<0
m1 = 5
m2 = -2
pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2)
# nx.barbell_graph(2,m) = nx.path_graph(m+4)
m1 = 2
m2 = 5
b = nx.barbell_graph(m1, m2)
assert is_isomorphic(b, nx.path_graph(m2 + 4))
m1 = 2
m2 = 10
b = nx.barbell_graph(m1, m2)
assert is_isomorphic(b, nx.path_graph(m2 + 4))
m1 = 2
m2 = 20
b = nx.barbell_graph(m1, m2)
assert is_isomorphic(b, nx.path_graph(m2 + 4))
pytest.raises(
nx.NetworkXError, nx.barbell_graph, m1, m2, create_using=nx.DiGraph()
)
mb = nx.barbell_graph(m1, m2, create_using=nx.MultiGraph())
assert edges_equal(mb.edges(), b.edges())
def test_binomial_tree(self):
graphs = (None, nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
for create_using in graphs:
for n in range(4):
b = nx.binomial_tree(n, create_using)
assert nx.number_of_nodes(b) == 2**n
assert nx.number_of_edges(b) == (2**n - 1)
def test_complete_graph(self):
# complete_graph(m) is a connected graph with
# m nodes and m*(m+1)/2 edges
for m in [0, 1, 3, 5]:
g = nx.complete_graph(m)
assert nx.number_of_nodes(g) == m
assert nx.number_of_edges(g) == m * (m - 1) // 2
mg = nx.complete_graph(m, create_using=nx.MultiGraph)
assert edges_equal(mg.edges(), g.edges())
g = nx.complete_graph("abc")
assert nodes_equal(g.nodes(), ["a", "b", "c"])
assert g.size() == 3
# creates a self-loop... should it? <backward compatible says yes>
g = nx.complete_graph("abcb")
assert nodes_equal(g.nodes(), ["a", "b", "c"])
assert g.size() == 4
g = nx.complete_graph("abcb", create_using=nx.MultiGraph)
assert nodes_equal(g.nodes(), ["a", "b", "c"])
assert g.size() == 6
def test_complete_digraph(self):
# complete_graph(m) is a connected graph with
# m nodes and m*(m+1)/2 edges
for m in [0, 1, 3, 5]:
g = nx.complete_graph(m, create_using=nx.DiGraph)
assert nx.number_of_nodes(g) == m
assert nx.number_of_edges(g) == m * (m - 1)
g = nx.complete_graph("abc", create_using=nx.DiGraph)
assert len(g) == 3
assert g.size() == 6
assert g.is_directed()
def test_circular_ladder_graph(self):
G = nx.circular_ladder_graph(5)
pytest.raises(
nx.NetworkXError, nx.circular_ladder_graph, 5, create_using=nx.DiGraph
)
mG = nx.circular_ladder_graph(5, create_using=nx.MultiGraph)
assert edges_equal(mG.edges(), G.edges())
def test_circulant_graph(self):
# Ci_n(1) is the cycle graph for all n
Ci6_1 = nx.circulant_graph(6, [1])
C6 = nx.cycle_graph(6)
assert edges_equal(Ci6_1.edges(), C6.edges())
# Ci_n(1, 2, ..., n div 2) is the complete graph for all n
Ci7 = nx.circulant_graph(7, [1, 2, 3])
K7 = nx.complete_graph(7)
assert edges_equal(Ci7.edges(), K7.edges())
# Ci_6(1, 3) is K_3,3 i.e. the utility graph
Ci6_1_3 = nx.circulant_graph(6, [1, 3])
K3_3 = nx.complete_bipartite_graph(3, 3)
assert is_isomorphic(Ci6_1_3, K3_3)
def test_cycle_graph(self):
G = nx.cycle_graph(4)
assert edges_equal(G.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)])
mG = nx.cycle_graph(4, create_using=nx.MultiGraph)
assert edges_equal(mG.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)])
G = nx.cycle_graph(4, create_using=nx.DiGraph)
assert not G.has_edge(2, 1)
assert G.has_edge(1, 2)
assert G.is_directed()
G = nx.cycle_graph("abc")
assert len(G) == 3
assert G.size() == 3
G = nx.cycle_graph("abcb")
assert len(G) == 3
assert G.size() == 2
g = nx.cycle_graph("abc", nx.DiGraph)
assert len(g) == 3
assert g.size() == 3
assert g.is_directed()
g = nx.cycle_graph("abcb", nx.DiGraph)
assert len(g) == 3
assert g.size() == 4
def test_dorogovtsev_goltsev_mendes_graph(self):
G = nx.dorogovtsev_goltsev_mendes_graph(0)
assert edges_equal(G.edges(), [(0, 1)])
assert nodes_equal(list(G), [0, 1])
G = nx.dorogovtsev_goltsev_mendes_graph(1)
assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)])
assert nx.average_clustering(G) == 1.0
assert nx.average_shortest_path_length(G) == 1.0
assert sorted(nx.triangles(G).values()) == [1, 1, 1]
assert nx.is_planar(G)
G = nx.dorogovtsev_goltsev_mendes_graph(2)
assert nx.number_of_nodes(G) == 6
assert nx.number_of_edges(G) == 9
assert nx.average_clustering(G) == 0.75
assert nx.average_shortest_path_length(G) == 1.4
assert nx.is_planar(G)
G = nx.dorogovtsev_goltsev_mendes_graph(10)
assert nx.number_of_nodes(G) == 29526
assert nx.number_of_edges(G) == 59049
assert G.degree(0) == 1024
assert G.degree(1) == 1024
assert G.degree(2) == 1024
with pytest.raises(nx.NetworkXError, match=r"n must be greater than"):
nx.dorogovtsev_goltsev_mendes_graph(-1)
with pytest.raises(nx.NetworkXError, match=r"directed graph not supported"):
nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.DiGraph)
with pytest.raises(nx.NetworkXError, match=r"multigraph not supported"):
nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.MultiGraph)
with pytest.raises(nx.NetworkXError):
nx.dorogovtsev_goltsev_mendes_graph(7, create_using=nx.MultiDiGraph)
def test_create_using(self):
G = nx.empty_graph()
assert isinstance(G, nx.Graph)
pytest.raises(TypeError, nx.empty_graph, create_using=0.0)
pytest.raises(TypeError, nx.empty_graph, create_using="Graph")
G = nx.empty_graph(create_using=nx.MultiGraph)
assert isinstance(G, nx.MultiGraph)
G = nx.empty_graph(create_using=nx.DiGraph)
assert isinstance(G, nx.DiGraph)
G = nx.empty_graph(create_using=nx.DiGraph, default=nx.MultiGraph)
assert isinstance(G, nx.DiGraph)
G = nx.empty_graph(create_using=None, default=nx.MultiGraph)
assert isinstance(G, nx.MultiGraph)
G = nx.empty_graph(default=nx.MultiGraph)
assert isinstance(G, nx.MultiGraph)
G = nx.path_graph(5)
H = nx.empty_graph(create_using=G)
assert not H.is_multigraph()
assert not H.is_directed()
assert len(H) == 0
assert G is H
H = nx.empty_graph(create_using=nx.MultiGraph())
assert H.is_multigraph()
assert not H.is_directed()
assert G is not H
# test for subclasses that also use typing.Protocol. See gh-6243
class Mixin(typing.Protocol):
pass
class MyGraph(Mixin, nx.DiGraph):
pass
G = nx.empty_graph(create_using=MyGraph)
def test_empty_graph(self):
G = nx.empty_graph()
assert nx.number_of_nodes(G) == 0
G = nx.empty_graph(42)
assert nx.number_of_nodes(G) == 42
assert nx.number_of_edges(G) == 0
G = nx.empty_graph("abc")
assert len(G) == 3
assert G.size() == 0
# create empty digraph
G = nx.empty_graph(42, create_using=nx.DiGraph(name="duh"))
assert nx.number_of_nodes(G) == 42
assert nx.number_of_edges(G) == 0
assert isinstance(G, nx.DiGraph)
# create empty multigraph
G = nx.empty_graph(42, create_using=nx.MultiGraph(name="duh"))
assert nx.number_of_nodes(G) == 42
assert nx.number_of_edges(G) == 0
assert isinstance(G, nx.MultiGraph)
# create empty graph from another
pete = nx.petersen_graph()
G = nx.empty_graph(42, create_using=pete)
assert nx.number_of_nodes(G) == 42
assert nx.number_of_edges(G) == 0
assert isinstance(G, nx.Graph)
def test_ladder_graph(self):
for i, G in [
(0, nx.empty_graph(0)),
(1, nx.path_graph(2)),
(2, nx.hypercube_graph(2)),
(10, nx.grid_graph([2, 10])),
]:
assert is_isomorphic(nx.ladder_graph(i), G)
pytest.raises(nx.NetworkXError, nx.ladder_graph, 2, create_using=nx.DiGraph)
g = nx.ladder_graph(2)
mg = nx.ladder_graph(2, create_using=nx.MultiGraph)
assert edges_equal(mg.edges(), g.edges())
@pytest.mark.parametrize(("m", "n"), [(3, 5), (4, 10), (3, 20)])
def test_lollipop_graph_right_sizes(self, m, n):
G = nx.lollipop_graph(m, n)
assert nx.number_of_nodes(G) == m + n
assert nx.number_of_edges(G) == m * (m - 1) / 2 + n
@pytest.mark.parametrize(("m", "n"), [("ab", ""), ("abc", "defg")])
def test_lollipop_graph_size_node_sequence(self, m, n):
G = nx.lollipop_graph(m, n)
assert nx.number_of_nodes(G) == len(m) + len(n)
assert nx.number_of_edges(G) == len(m) * (len(m) - 1) / 2 + len(n)
def test_lollipop_graph_exceptions(self):
# Raise NetworkXError if m<2
pytest.raises(nx.NetworkXError, nx.lollipop_graph, -1, 2)
pytest.raises(nx.NetworkXError, nx.lollipop_graph, 1, 20)
pytest.raises(nx.NetworkXError, nx.lollipop_graph, "", 20)
pytest.raises(nx.NetworkXError, nx.lollipop_graph, "a", 20)
# Raise NetworkXError if n<0
pytest.raises(nx.NetworkXError, nx.lollipop_graph, 5, -2)
# raise NetworkXError if create_using is directed
with pytest.raises(nx.NetworkXError):
nx.lollipop_graph(2, 20, create_using=nx.DiGraph)
with pytest.raises(nx.NetworkXError):
nx.lollipop_graph(2, 20, create_using=nx.MultiDiGraph)
@pytest.mark.parametrize(("m", "n"), [(2, 0), (2, 5), (2, 10), ("ab", 20)])
def test_lollipop_graph_same_as_path_when_m1_is_2(self, m, n):
G = nx.lollipop_graph(m, n)
assert is_isomorphic(G, nx.path_graph(n + 2))
def test_lollipop_graph_for_multigraph(self):
G = nx.lollipop_graph(5, 20)
MG = nx.lollipop_graph(5, 20, create_using=nx.MultiGraph)
assert edges_equal(MG.edges(), G.edges())
@pytest.mark.parametrize(
("m", "n"),
[(4, "abc"), ("abcd", 3), ([1, 2, 3, 4], "abc"), ("abcd", [1, 2, 3])],
)
def test_lollipop_graph_mixing_input_types(self, m, n):
expected = nx.compose(nx.complete_graph(4), nx.path_graph(range(100, 103)))
expected.add_edge(0, 100) # Connect complete graph and path graph
assert is_isomorphic(nx.lollipop_graph(m, n), expected)
def test_lollipop_graph_non_builtin_ints(self):
np = pytest.importorskip("numpy")
G = nx.lollipop_graph(np.int32(4), np.int64(3))
expected = nx.compose(nx.complete_graph(4), nx.path_graph(range(100, 103)))
expected.add_edge(0, 100) # Connect complete graph and path graph
assert is_isomorphic(G, expected)
def test_null_graph(self):
assert nx.number_of_nodes(nx.null_graph()) == 0
def test_path_graph(self):
p = nx.path_graph(0)
assert is_isomorphic(p, nx.null_graph())
p = nx.path_graph(1)
assert is_isomorphic(p, nx.empty_graph(1))
p = nx.path_graph(10)
assert nx.is_connected(p)
assert sorted(d for n, d in p.degree()) == [1, 1, 2, 2, 2, 2, 2, 2, 2, 2]
assert p.order() - 1 == p.size()
dp = nx.path_graph(3, create_using=nx.DiGraph)
assert dp.has_edge(0, 1)
assert not dp.has_edge(1, 0)
mp = nx.path_graph(10, create_using=nx.MultiGraph)
assert edges_equal(mp.edges(), p.edges())
G = nx.path_graph("abc")
assert len(G) == 3
assert G.size() == 2
G = nx.path_graph("abcb")
assert len(G) == 3
assert G.size() == 2
g = nx.path_graph("abc", nx.DiGraph)
assert len(g) == 3
assert g.size() == 2
assert g.is_directed()
g = nx.path_graph("abcb", nx.DiGraph)
assert len(g) == 3
assert g.size() == 3
G = nx.path_graph((1, 2, 3, 2, 4))
assert G.has_edge(2, 4)
def test_star_graph(self):
assert is_isomorphic(nx.star_graph(""), nx.empty_graph(0))
assert is_isomorphic(nx.star_graph([]), nx.empty_graph(0))
assert is_isomorphic(nx.star_graph(0), nx.empty_graph(1))
assert is_isomorphic(nx.star_graph(1), nx.path_graph(2))
assert is_isomorphic(nx.star_graph(2), nx.path_graph(3))
assert is_isomorphic(nx.star_graph(5), nx.complete_bipartite_graph(1, 5))
s = nx.star_graph(10)
assert sorted(d for n, d in s.degree()) == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10]
pytest.raises(nx.NetworkXError, nx.star_graph, 10, create_using=nx.DiGraph)
ms = nx.star_graph(10, create_using=nx.MultiGraph)
assert edges_equal(ms.edges(), s.edges())
G = nx.star_graph("abc")
assert len(G) == 3
assert G.size() == 2
G = nx.star_graph("abcb")
assert len(G) == 3
assert G.size() == 2
G = nx.star_graph("abcb", create_using=nx.MultiGraph)
assert len(G) == 3
assert G.size() == 3
G = nx.star_graph("abcdefg")
assert len(G) == 7
assert G.size() == 6
def test_non_int_integers_for_star_graph(self):
np = pytest.importorskip("numpy")
G = nx.star_graph(np.int32(3))
assert len(G) == 4
assert G.size() == 3
@pytest.mark.parametrize(("m", "n"), [(3, 0), (3, 5), (4, 10), (3, 20)])
def test_tadpole_graph_right_sizes(self, m, n):
G = nx.tadpole_graph(m, n)
assert nx.number_of_nodes(G) == m + n
assert nx.number_of_edges(G) == m + n - (m == 2)
@pytest.mark.parametrize(("m", "n"), [("ab", ""), ("ab", "c"), ("abc", "defg")])
def test_tadpole_graph_size_node_sequences(self, m, n):
G = nx.tadpole_graph(m, n)
assert nx.number_of_nodes(G) == len(m) + len(n)
assert nx.number_of_edges(G) == len(m) + len(n) - (len(m) == 2)
def test_tadpole_graph_exceptions(self):
# Raise NetworkXError if m<2
pytest.raises(nx.NetworkXError, nx.tadpole_graph, -1, 3)
pytest.raises(nx.NetworkXError, nx.tadpole_graph, 0, 3)
pytest.raises(nx.NetworkXError, nx.tadpole_graph, 1, 3)
# Raise NetworkXError if n<0
pytest.raises(nx.NetworkXError, nx.tadpole_graph, 5, -2)
# Raise NetworkXError for digraphs
with pytest.raises(nx.NetworkXError):
nx.tadpole_graph(2, 20, create_using=nx.DiGraph)
with pytest.raises(nx.NetworkXError):
nx.tadpole_graph(2, 20, create_using=nx.MultiDiGraph)
@pytest.mark.parametrize(("m", "n"), [(2, 0), (2, 5), (2, 10), ("ab", 20)])
def test_tadpole_graph_same_as_path_when_m_is_2(self, m, n):
G = nx.tadpole_graph(m, n)
assert is_isomorphic(G, nx.path_graph(n + 2))
@pytest.mark.parametrize("m", [4, 7])
def test_tadpole_graph_same_as_cycle_when_m2_is_0(self, m):
G = nx.tadpole_graph(m, 0)
assert is_isomorphic(G, nx.cycle_graph(m))
def test_tadpole_graph_for_multigraph(self):
G = nx.tadpole_graph(5, 20)
MG = nx.tadpole_graph(5, 20, create_using=nx.MultiGraph)
assert edges_equal(MG.edges(), G.edges())
@pytest.mark.parametrize(
("m", "n"),
[(4, "abc"), ("abcd", 3), ([1, 2, 3, 4], "abc"), ("abcd", [1, 2, 3])],
)
def test_tadpole_graph_mixing_input_types(self, m, n):
expected = nx.compose(nx.cycle_graph(4), nx.path_graph(range(100, 103)))
expected.add_edge(0, 100) # Connect cycle and path
assert is_isomorphic(nx.tadpole_graph(m, n), expected)
def test_tadpole_graph_non_builtin_integers(self):
np = pytest.importorskip("numpy")
G = nx.tadpole_graph(np.int32(4), np.int64(3))
expected = nx.compose(nx.cycle_graph(4), nx.path_graph(range(100, 103)))
expected.add_edge(0, 100) # Connect cycle and path
assert is_isomorphic(G, expected)
def test_trivial_graph(self):
assert nx.number_of_nodes(nx.trivial_graph()) == 1
def test_turan_graph(self):
assert nx.number_of_edges(nx.turan_graph(13, 4)) == 63
assert is_isomorphic(
nx.turan_graph(13, 4), nx.complete_multipartite_graph(3, 4, 3, 3)
)
def test_wheel_graph(self):
for n, G in [
("", nx.null_graph()),
(0, nx.null_graph()),
(1, nx.empty_graph(1)),
(2, nx.path_graph(2)),
(3, nx.complete_graph(3)),
(4, nx.complete_graph(4)),
]:
g = nx.wheel_graph(n)
assert is_isomorphic(g, G)
g = nx.wheel_graph(10)
assert sorted(d for n, d in g.degree()) == [3, 3, 3, 3, 3, 3, 3, 3, 3, 9]
pytest.raises(nx.NetworkXError, nx.wheel_graph, 10, create_using=nx.DiGraph)
mg = nx.wheel_graph(10, create_using=nx.MultiGraph())
assert edges_equal(mg.edges(), g.edges())
G = nx.wheel_graph("abc")
assert len(G) == 3
assert G.size() == 3
G = nx.wheel_graph("abcb")
assert len(G) == 3
assert G.size() == 4
G = nx.wheel_graph("abcb", nx.MultiGraph)
assert len(G) == 3
assert G.size() == 6
def test_non_int_integers_for_wheel_graph(self):
np = pytest.importorskip("numpy")
G = nx.wheel_graph(np.int32(3))
assert len(G) == 3
assert G.size() == 3
def test_complete_0_partite_graph(self):
"""Tests that the complete 0-partite graph is the null graph."""
G = nx.complete_multipartite_graph()
H = nx.null_graph()
assert nodes_equal(G, H)
assert edges_equal(G.edges(), H.edges())
def test_complete_1_partite_graph(self):
"""Tests that the complete 1-partite graph is the empty graph."""
G = nx.complete_multipartite_graph(3)
H = nx.empty_graph(3)
assert nodes_equal(G, H)
assert edges_equal(G.edges(), H.edges())
def test_complete_2_partite_graph(self):
"""Tests that the complete 2-partite graph is the complete bipartite
graph.
"""
G = nx.complete_multipartite_graph(2, 3)
H = nx.complete_bipartite_graph(2, 3)
assert nodes_equal(G, H)
assert edges_equal(G.edges(), H.edges())
def test_complete_multipartite_graph(self):
"""Tests for generating the complete multipartite graph."""
G = nx.complete_multipartite_graph(2, 3, 4)
blocks = [(0, 1), (2, 3, 4), (5, 6, 7, 8)]
# Within each block, no two vertices should be adjacent.
for block in blocks:
for u, v in itertools.combinations_with_replacement(block, 2):
assert v not in G[u]
assert G.nodes[u] == G.nodes[v]
# Across blocks, all vertices should be adjacent.
for block1, block2 in itertools.combinations(blocks, 2):
for u, v in itertools.product(block1, block2):
assert v in G[u]
assert G.nodes[u] != G.nodes[v]
with pytest.raises(nx.NetworkXError, match="Negative number of nodes"):
nx.complete_multipartite_graph(2, -3, 4)
def test_kneser_graph(self):
# the petersen graph is a special case of the kneser graph when n=5 and k=2
assert is_isomorphic(nx.kneser_graph(5, 2), nx.petersen_graph())
# when k is 1, the kneser graph returns a complete graph with n vertices
for i in range(1, 7):
assert is_isomorphic(nx.kneser_graph(i, 1), nx.complete_graph(i))
# the kneser graph of n and n-1 is the empty graph with n vertices
for j in range(3, 7):
assert is_isomorphic(nx.kneser_graph(j, j - 1), nx.empty_graph(j))
# in general the number of edges of the kneser graph is equal to
# (n choose k) times (n-k choose k) divided by 2
assert nx.number_of_edges(nx.kneser_graph(8, 3)) == 280

View File

@ -0,0 +1,18 @@
"""Unit tests for the :mod:`networkx.generators.cographs` module."""
import networkx as nx
def test_random_cograph():
n = 3
G = nx.random_cograph(n)
assert len(G) == 2**n
# Every connected subgraph of G has diameter <= 2
if nx.is_connected(G):
assert nx.diameter(G) <= 2
else:
components = nx.connected_components(G)
for component in components:
assert nx.diameter(G.subgraph(component)) <= 2

View File

@ -0,0 +1,362 @@
import pytest
import networkx as nx
def test_random_partition_graph():
G = nx.random_partition_graph([3, 3, 3], 1, 0, seed=42)
C = G.graph["partition"]
assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}]
assert len(G) == 9
assert len(list(G.edges())) == 9
G = nx.random_partition_graph([3, 3, 3], 0, 1)
C = G.graph["partition"]
assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}]
assert len(G) == 9
assert len(list(G.edges())) == 27
G = nx.random_partition_graph([3, 3, 3], 1, 0, directed=True)
C = G.graph["partition"]
assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}]
assert len(G) == 9
assert len(list(G.edges())) == 18
G = nx.random_partition_graph([3, 3, 3], 0, 1, directed=True)
C = G.graph["partition"]
assert C == [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}]
assert len(G) == 9
assert len(list(G.edges())) == 54
G = nx.random_partition_graph([1, 2, 3, 4, 5], 0.5, 0.1)
C = G.graph["partition"]
assert C == [{0}, {1, 2}, {3, 4, 5}, {6, 7, 8, 9}, {10, 11, 12, 13, 14}]
assert len(G) == 15
rpg = nx.random_partition_graph
pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 1.1, 0.1)
pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], -0.1, 0.1)
pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, 1.1)
pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, -0.1)
def test_planted_partition_graph():
G = nx.planted_partition_graph(4, 3, 1, 0, seed=42)
C = G.graph["partition"]
assert len(C) == 4
assert len(G) == 12
assert len(list(G.edges())) == 12
G = nx.planted_partition_graph(4, 3, 0, 1)
C = G.graph["partition"]
assert len(C) == 4
assert len(G) == 12
assert len(list(G.edges())) == 54
G = nx.planted_partition_graph(10, 4, 0.5, 0.1, seed=42)
C = G.graph["partition"]
assert len(C) == 10
assert len(G) == 40
G = nx.planted_partition_graph(4, 3, 1, 0, directed=True)
C = G.graph["partition"]
assert len(C) == 4
assert len(G) == 12
assert len(list(G.edges())) == 24
G = nx.planted_partition_graph(4, 3, 0, 1, directed=True)
C = G.graph["partition"]
assert len(C) == 4
assert len(G) == 12
assert len(list(G.edges())) == 108
G = nx.planted_partition_graph(10, 4, 0.5, 0.1, seed=42, directed=True)
C = G.graph["partition"]
assert len(C) == 10
assert len(G) == 40
ppg = nx.planted_partition_graph
pytest.raises(nx.NetworkXError, ppg, 3, 3, 1.1, 0.1)
pytest.raises(nx.NetworkXError, ppg, 3, 3, -0.1, 0.1)
pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, 1.1)
pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, -0.1)
def test_relaxed_caveman_graph():
G = nx.relaxed_caveman_graph(4, 3, 0)
assert len(G) == 12
G = nx.relaxed_caveman_graph(4, 3, 1)
assert len(G) == 12
G = nx.relaxed_caveman_graph(4, 3, 0.5)
assert len(G) == 12
G = nx.relaxed_caveman_graph(4, 3, 0.5, seed=42)
assert len(G) == 12
def test_connected_caveman_graph():
G = nx.connected_caveman_graph(4, 3)
assert len(G) == 12
G = nx.connected_caveman_graph(1, 5)
K5 = nx.complete_graph(5)
K5.remove_edge(3, 4)
assert nx.is_isomorphic(G, K5)
# need at least 2 nodes in each clique
pytest.raises(nx.NetworkXError, nx.connected_caveman_graph, 4, 1)
def test_caveman_graph():
G = nx.caveman_graph(4, 3)
assert len(G) == 12
G = nx.caveman_graph(5, 1)
E5 = nx.empty_graph(5)
assert nx.is_isomorphic(G, E5)
G = nx.caveman_graph(1, 5)
K5 = nx.complete_graph(5)
assert nx.is_isomorphic(G, K5)
def test_gaussian_random_partition_graph():
G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01)
assert len(G) == 100
G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01, directed=True)
assert len(G) == 100
G = nx.gaussian_random_partition_graph(
100, 10, 10, 0.3, 0.01, directed=False, seed=42
)
assert len(G) == 100
assert not isinstance(G, nx.DiGraph)
G = nx.gaussian_random_partition_graph(
100, 10, 10, 0.3, 0.01, directed=True, seed=42
)
assert len(G) == 100
assert isinstance(G, nx.DiGraph)
pytest.raises(
nx.NetworkXError, nx.gaussian_random_partition_graph, 100, 101, 10, 1, 0
)
# Test when clusters are likely less than 1
G = nx.gaussian_random_partition_graph(10, 0.5, 0.5, 0.5, 0.5, seed=1)
assert len(G) == 10
def test_ring_of_cliques():
for i in range(2, 20, 3):
for j in range(2, 20, 3):
G = nx.ring_of_cliques(i, j)
assert G.number_of_nodes() == i * j
if i != 2 or j != 1:
expected_num_edges = i * (((j * (j - 1)) // 2) + 1)
else:
# the edge that already exists cannot be duplicated
expected_num_edges = i * (((j * (j - 1)) // 2) + 1) - 1
assert G.number_of_edges() == expected_num_edges
with pytest.raises(
nx.NetworkXError, match="A ring of cliques must have at least two cliques"
):
nx.ring_of_cliques(1, 5)
with pytest.raises(
nx.NetworkXError, match="The cliques must have at least two nodes"
):
nx.ring_of_cliques(3, 0)
def test_windmill_graph():
for n in range(2, 20, 3):
for k in range(2, 20, 3):
G = nx.windmill_graph(n, k)
assert G.number_of_nodes() == (k - 1) * n + 1
assert G.number_of_edges() == n * k * (k - 1) / 2
assert G.degree(0) == G.number_of_nodes() - 1
for i in range(1, G.number_of_nodes()):
assert G.degree(i) == k - 1
with pytest.raises(
nx.NetworkXError, match="A windmill graph must have at least two cliques"
):
nx.windmill_graph(1, 3)
with pytest.raises(
nx.NetworkXError, match="The cliques must have at least two nodes"
):
nx.windmill_graph(3, 0)
def test_stochastic_block_model():
sizes = [75, 75, 300]
probs = [[0.25, 0.05, 0.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]]
G = nx.stochastic_block_model(sizes, probs, seed=0)
C = G.graph["partition"]
assert len(C) == 3
assert len(G) == 450
assert G.size() == 22160
GG = nx.stochastic_block_model(sizes, probs, range(450), seed=0)
assert G.nodes == GG.nodes
# Test Exceptions
sbm = nx.stochastic_block_model
badnodelist = list(range(400)) # not enough nodes to match sizes
badprobs1 = [[0.25, 0.05, 1.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]]
badprobs2 = [[0.25, 0.05, 0.02], [0.05, -0.35, 0.07], [0.02, 0.07, 0.40]]
probs_rect1 = [[0.25, 0.05, 0.02], [0.05, -0.35, 0.07]]
probs_rect2 = [[0.25, 0.05], [0.05, -0.35], [0.02, 0.07]]
asymprobs = [[0.25, 0.05, 0.01], [0.05, -0.35, 0.07], [0.02, 0.07, 0.40]]
pytest.raises(nx.NetworkXException, sbm, sizes, badprobs1)
pytest.raises(nx.NetworkXException, sbm, sizes, badprobs2)
pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect1, directed=True)
pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect2, directed=True)
pytest.raises(nx.NetworkXException, sbm, sizes, asymprobs, directed=False)
pytest.raises(nx.NetworkXException, sbm, sizes, probs, badnodelist)
nodelist = [0] + list(range(449)) # repeated node name in nodelist
pytest.raises(nx.NetworkXException, sbm, sizes, probs, nodelist)
# Extra keyword arguments test
GG = nx.stochastic_block_model(sizes, probs, seed=0, selfloops=True)
assert G.nodes == GG.nodes
GG = nx.stochastic_block_model(sizes, probs, selfloops=True, directed=True)
assert G.nodes == GG.nodes
GG = nx.stochastic_block_model(sizes, probs, seed=0, sparse=False)
assert G.nodes == GG.nodes
def test_generator():
n = 250
tau1 = 3
tau2 = 1.5
mu = 0.1
G = nx.LFR_benchmark_graph(
n, tau1, tau2, mu, average_degree=5, min_community=20, seed=10
)
assert len(G) == 250
C = {frozenset(G.nodes[v]["community"]) for v in G}
assert nx.community.is_partition(G.nodes(), C)
def test_invalid_tau1():
with pytest.raises(nx.NetworkXError, match="tau2 must be greater than one"):
n = 100
tau1 = 2
tau2 = 1
mu = 0.1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2)
def test_invalid_tau2():
with pytest.raises(nx.NetworkXError, match="tau1 must be greater than one"):
n = 100
tau1 = 1
tau2 = 2
mu = 0.1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2)
def test_mu_too_large():
with pytest.raises(nx.NetworkXError, match="mu must be in the interval \\[0, 1\\]"):
n = 100
tau1 = 2
tau2 = 2
mu = 1.1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2)
def test_mu_too_small():
with pytest.raises(nx.NetworkXError, match="mu must be in the interval \\[0, 1\\]"):
n = 100
tau1 = 2
tau2 = 2
mu = -1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2)
def test_both_degrees_none():
with pytest.raises(
nx.NetworkXError,
match="Must assign exactly one of min_degree and average_degree",
):
n = 100
tau1 = 2
tau2 = 2
mu = 1
nx.LFR_benchmark_graph(n, tau1, tau2, mu)
def test_neither_degrees_none():
with pytest.raises(
nx.NetworkXError,
match="Must assign exactly one of min_degree and average_degree",
):
n = 100
tau1 = 2
tau2 = 2
mu = 1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, average_degree=5)
def test_max_iters_exceeded():
with pytest.raises(
nx.ExceededMaxIterations,
match="Could not assign communities; try increasing min_community",
):
n = 10
tau1 = 2
tau2 = 2
mu = 0.1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, max_iters=10, seed=1)
def test_max_deg_out_of_range():
with pytest.raises(
nx.NetworkXError, match="max_degree must be in the interval \\(0, n\\]"
):
n = 10
tau1 = 2
tau2 = 2
mu = 0.1
nx.LFR_benchmark_graph(
n, tau1, tau2, mu, max_degree=n + 1, max_iters=10, seed=1
)
def test_max_community():
n = 250
tau1 = 3
tau2 = 1.5
mu = 0.1
G = nx.LFR_benchmark_graph(
n,
tau1,
tau2,
mu,
average_degree=5,
max_degree=100,
min_community=50,
max_community=200,
seed=10,
)
assert len(G) == 250
C = {frozenset(G.nodes[v]["community"]) for v in G}
assert nx.community.is_partition(G.nodes(), C)
def test_powerlaw_iterations_exceeded():
with pytest.raises(
nx.ExceededMaxIterations, match="Could not create power law sequence"
):
n = 100
tau1 = 2
tau2 = 2
mu = 1
nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, max_iters=0)
def test_no_scipy_zeta():
zeta2 = 1.6449340668482264
assert abs(zeta2 - nx.generators.community._hurwitz_zeta(2, 1, 0.0001)) < 0.01
def test_generate_min_degree_itr():
with pytest.raises(
nx.ExceededMaxIterations, match="Could not match average_degree"
):
nx.generators.community._generate_min_degree(2, 2, 1, 0.01, 0)

View File

@ -0,0 +1,230 @@
import pytest
import networkx as nx
class TestConfigurationModel:
"""Unit tests for the :func:`~networkx.configuration_model`
function.
"""
def test_empty_degree_sequence(self):
"""Tests that an empty degree sequence yields the null graph."""
G = nx.configuration_model([])
assert len(G) == 0
def test_degree_zero(self):
"""Tests that a degree sequence of all zeros yields the empty
graph.
"""
G = nx.configuration_model([0, 0, 0])
assert len(G) == 3
assert G.number_of_edges() == 0
def test_degree_sequence(self):
"""Tests that the degree sequence of the generated graph matches
the input degree sequence.
"""
deg_seq = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]
G = nx.configuration_model(deg_seq, seed=12345678)
assert sorted((d for n, d in G.degree()), reverse=True) == [
5,
3,
3,
3,
3,
2,
2,
2,
1,
1,
1,
]
assert sorted((d for n, d in G.degree(range(len(deg_seq)))), reverse=True) == [
5,
3,
3,
3,
3,
2,
2,
2,
1,
1,
1,
]
def test_random_seed(self):
"""Tests that each call with the same random seed generates the
same graph.
"""
deg_seq = [3] * 12
G1 = nx.configuration_model(deg_seq, seed=1000)
G2 = nx.configuration_model(deg_seq, seed=1000)
assert nx.is_isomorphic(G1, G2)
G1 = nx.configuration_model(deg_seq, seed=10)
G2 = nx.configuration_model(deg_seq, seed=10)
assert nx.is_isomorphic(G1, G2)
def test_directed_disallowed(self):
"""Tests that attempting to create a configuration model graph
using a directed graph yields an exception.
"""
with pytest.raises(nx.NetworkXNotImplemented):
nx.configuration_model([], create_using=nx.DiGraph())
def test_odd_degree_sum(self):
"""Tests that a degree sequence whose sum is odd yields an
exception.
"""
with pytest.raises(nx.NetworkXError):
nx.configuration_model([1, 2])
def test_directed_configuration_raise_unequal():
with pytest.raises(nx.NetworkXError):
zin = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1]
zout = [5, 3, 3, 3, 3, 2, 2, 2, 1, 2]
nx.directed_configuration_model(zin, zout)
def test_directed_configuration_model():
G = nx.directed_configuration_model([], [], seed=0)
assert len(G) == 0
def test_simple_directed_configuration_model():
G = nx.directed_configuration_model([1, 1], [1, 1], seed=0)
assert len(G) == 2
def test_expected_degree_graph_empty():
# empty graph has empty degree sequence
deg_seq = []
G = nx.expected_degree_graph(deg_seq)
assert dict(G.degree()) == {}
def test_expected_degree_graph():
# test that fixed seed delivers the same graph
deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
G1 = nx.expected_degree_graph(deg_seq, seed=1000)
assert len(G1) == 12
G2 = nx.expected_degree_graph(deg_seq, seed=1000)
assert nx.is_isomorphic(G1, G2)
G1 = nx.expected_degree_graph(deg_seq, seed=10)
G2 = nx.expected_degree_graph(deg_seq, seed=10)
assert nx.is_isomorphic(G1, G2)
def test_expected_degree_graph_selfloops():
deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
G1 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False)
G2 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False)
assert nx.is_isomorphic(G1, G2)
assert len(G1) == 12
def test_expected_degree_graph_skew():
deg_seq = [10, 2, 2, 2, 2]
G1 = nx.expected_degree_graph(deg_seq, seed=1000)
G2 = nx.expected_degree_graph(deg_seq, seed=1000)
assert nx.is_isomorphic(G1, G2)
assert len(G1) == 5
def test_havel_hakimi_construction():
G = nx.havel_hakimi_graph([])
assert len(G) == 0
z = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]
pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z)
z = ["A", 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]
pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z)
z = [5, 4, 3, 3, 3, 2, 2, 2]
G = nx.havel_hakimi_graph(z)
G = nx.configuration_model(z)
z = [6, 5, 4, 4, 2, 1, 1, 1]
pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z)
z = [10, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2]
G = nx.havel_hakimi_graph(z)
pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z, create_using=nx.DiGraph())
def test_directed_havel_hakimi():
# Test range of valid directed degree sequences
n, r = 100, 10
p = 1.0 / r
for i in range(r):
G1 = nx.erdos_renyi_graph(n, p * (i + 1), None, True)
din1 = [d for n, d in G1.in_degree()]
dout1 = [d for n, d in G1.out_degree()]
G2 = nx.directed_havel_hakimi_graph(din1, dout1)
din2 = [d for n, d in G2.in_degree()]
dout2 = [d for n, d in G2.out_degree()]
assert sorted(din1) == sorted(din2)
assert sorted(dout1) == sorted(dout2)
# Test non-graphical sequence
dout = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]
din = [103, 102, 102, 102, 102, 102, 102, 102, 102, 102]
pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout)
# Test valid sequences
dout = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4]
din = [2, 2, 2, 2, 2, 2, 2, 2, 0, 2]
G2 = nx.directed_havel_hakimi_graph(din, dout)
dout2 = (d for n, d in G2.out_degree())
din2 = (d for n, d in G2.in_degree())
assert sorted(dout) == sorted(dout2)
assert sorted(din) == sorted(din2)
# Test unequal sums
din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout)
# Test for negative values
din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2]
pytest.raises(nx.exception.NetworkXError, nx.directed_havel_hakimi_graph, din, dout)
def test_degree_sequence_tree():
z = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4]
G = nx.degree_sequence_tree(z)
assert len(G) == len(z)
assert len(list(G.edges())) == sum(z) / 2
pytest.raises(
nx.NetworkXError, nx.degree_sequence_tree, z, create_using=nx.DiGraph()
)
z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4]
pytest.raises(nx.NetworkXError, nx.degree_sequence_tree, z)
def test_random_degree_sequence_graph():
d = [1, 2, 2, 3]
G = nx.random_degree_sequence_graph(d, seed=42)
assert d == sorted(d for n, d in G.degree())
def test_random_degree_sequence_graph_raise():
z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4]
pytest.raises(nx.NetworkXUnfeasible, nx.random_degree_sequence_graph, z)
def test_random_degree_sequence_large():
G1 = nx.fast_gnp_random_graph(100, 0.1, seed=42)
d1 = (d for n, d in G1.degree())
G2 = nx.random_degree_sequence_graph(d1, seed=42)
d2 = (d for n, d in G2.degree())
assert sorted(d1) == sorted(d2)

View File

@ -0,0 +1,163 @@
"""Generators - Directed Graphs
----------------------------
"""
import pytest
import networkx as nx
from networkx.classes import Graph, MultiDiGraph
from networkx.generators.directed import (
gn_graph,
gnc_graph,
gnr_graph,
random_k_out_graph,
random_uniform_k_out_graph,
scale_free_graph,
)
class TestGeneratorsDirected:
def test_smoke_test_random_graphs(self):
gn_graph(100)
gnr_graph(100, 0.5)
gnc_graph(100)
scale_free_graph(100)
gn_graph(100, seed=42)
gnr_graph(100, 0.5, seed=42)
gnc_graph(100, seed=42)
scale_free_graph(100, seed=42)
def test_create_using_keyword_arguments(self):
pytest.raises(nx.NetworkXError, gn_graph, 100, create_using=Graph())
pytest.raises(nx.NetworkXError, gnr_graph, 100, 0.5, create_using=Graph())
pytest.raises(nx.NetworkXError, gnc_graph, 100, create_using=Graph())
G = gn_graph(100, seed=1)
MG = gn_graph(100, create_using=MultiDiGraph(), seed=1)
assert sorted(G.edges()) == sorted(MG.edges())
G = gnr_graph(100, 0.5, seed=1)
MG = gnr_graph(100, 0.5, create_using=MultiDiGraph(), seed=1)
assert sorted(G.edges()) == sorted(MG.edges())
G = gnc_graph(100, seed=1)
MG = gnc_graph(100, create_using=MultiDiGraph(), seed=1)
assert sorted(G.edges()) == sorted(MG.edges())
G = scale_free_graph(
100,
alpha=0.3,
beta=0.4,
gamma=0.3,
delta_in=0.3,
delta_out=0.1,
initial_graph=nx.cycle_graph(4, create_using=MultiDiGraph),
seed=1,
)
pytest.raises(ValueError, scale_free_graph, 100, 0.5, 0.4, 0.3)
pytest.raises(ValueError, scale_free_graph, 100, alpha=-0.3)
pytest.raises(ValueError, scale_free_graph, 100, beta=-0.3)
pytest.raises(ValueError, scale_free_graph, 100, gamma=-0.3)
def test_parameters(self):
G = nx.DiGraph()
G.add_node(0)
def kernel(x):
return x
assert nx.is_isomorphic(gn_graph(1), G)
assert nx.is_isomorphic(gn_graph(1, kernel=kernel), G)
assert nx.is_isomorphic(gnc_graph(1), G)
assert nx.is_isomorphic(gnr_graph(1, 0.5), G)
def test_scale_free_graph_negative_delta():
with pytest.raises(ValueError, match="delta_in must be >= 0."):
scale_free_graph(10, delta_in=-1)
with pytest.raises(ValueError, match="delta_out must be >= 0."):
scale_free_graph(10, delta_out=-1)
def test_non_numeric_ordering():
G = MultiDiGraph([("a", "b"), ("b", "c"), ("c", "a")])
s = scale_free_graph(3, initial_graph=G)
assert len(s) == 3
assert len(s.edges) == 3
@pytest.mark.parametrize("ig", (nx.Graph(), nx.DiGraph([(0, 1)])))
def test_scale_free_graph_initial_graph_kwarg(ig):
with pytest.raises(nx.NetworkXError):
scale_free_graph(100, initial_graph=ig)
class TestRandomKOutGraph:
"""Unit tests for the
:func:`~networkx.generators.directed.random_k_out_graph` function.
"""
def test_regularity(self):
"""Tests that the generated graph is `k`-out-regular."""
n = 10
k = 3
alpha = 1
G = random_k_out_graph(n, k, alpha)
assert all(d == k for v, d in G.out_degree())
G = random_k_out_graph(n, k, alpha, seed=42)
assert all(d == k for v, d in G.out_degree())
def test_no_self_loops(self):
"""Tests for forbidding self-loops."""
n = 10
k = 3
alpha = 1
G = random_k_out_graph(n, k, alpha, self_loops=False)
assert nx.number_of_selfloops(G) == 0
def test_negative_alpha(self):
with pytest.raises(ValueError, match="alpha must be positive"):
random_k_out_graph(10, 3, -1)
class TestUniformRandomKOutGraph:
"""Unit tests for the
:func:`~networkx.generators.directed.random_uniform_k_out_graph`
function.
"""
def test_regularity(self):
"""Tests that the generated graph is `k`-out-regular."""
n = 10
k = 3
G = random_uniform_k_out_graph(n, k)
assert all(d == k for v, d in G.out_degree())
G = random_uniform_k_out_graph(n, k, seed=42)
assert all(d == k for v, d in G.out_degree())
def test_no_self_loops(self):
"""Tests for forbidding self-loops."""
n = 10
k = 3
G = random_uniform_k_out_graph(n, k, self_loops=False)
assert nx.number_of_selfloops(G) == 0
assert all(d == k for v, d in G.out_degree())
def test_with_replacement(self):
n = 10
k = 3
G = random_uniform_k_out_graph(n, k, with_replacement=True)
assert G.is_multigraph()
assert all(d == k for v, d in G.out_degree())
n = 10
k = 9
G = random_uniform_k_out_graph(n, k, with_replacement=False, self_loops=False)
assert nx.number_of_selfloops(G) == 0
assert all(d == k for v, d in G.out_degree())
def test_without_replacement(self):
n = 10
k = 3
G = random_uniform_k_out_graph(n, k, with_replacement=False)
assert not G.is_multigraph()
assert all(d == k for v, d in G.out_degree())

View File

@ -0,0 +1,103 @@
"""Unit tests for the :mod:`networkx.generators.duplication` module."""
import pytest
import networkx as nx
class TestDuplicationDivergenceGraph:
"""Unit tests for the
:func:`networkx.generators.duplication.duplication_divergence_graph`
function.
"""
def test_final_size(self):
G = nx.duplication_divergence_graph(3, p=1)
assert len(G) == 3
G = nx.duplication_divergence_graph(3, p=1, seed=42)
assert len(G) == 3
def test_probability_too_large(self):
with pytest.raises(nx.NetworkXError):
nx.duplication_divergence_graph(3, p=2)
def test_probability_too_small(self):
with pytest.raises(nx.NetworkXError):
nx.duplication_divergence_graph(3, p=-1)
def test_non_extreme_probability_value(self):
G = nx.duplication_divergence_graph(6, p=0.3, seed=42)
assert len(G) == 6
assert list(G.degree()) == [(0, 2), (1, 3), (2, 2), (3, 3), (4, 1), (5, 1)]
def test_minimum_desired_nodes(self):
with pytest.raises(
nx.NetworkXError, match=".*n must be greater than or equal to 2"
):
nx.duplication_divergence_graph(1, p=1)
def test_create_using(self):
class DummyGraph(nx.Graph):
pass
class DummyDiGraph(nx.DiGraph):
pass
G = nx.duplication_divergence_graph(6, 0.3, seed=42, create_using=DummyGraph)
assert isinstance(G, DummyGraph)
with pytest.raises(nx.NetworkXError, match="create_using must not be directed"):
nx.duplication_divergence_graph(6, 0.3, seed=42, create_using=DummyDiGraph)
class TestPartialDuplicationGraph:
"""Unit tests for the
:func:`networkx.generators.duplication.partial_duplication_graph`
function.
"""
def test_final_size(self):
N = 10
n = 5
p = 0.5
q = 0.5
G = nx.partial_duplication_graph(N, n, p, q)
assert len(G) == N
G = nx.partial_duplication_graph(N, n, p, q, seed=42)
assert len(G) == N
def test_initial_clique_size(self):
N = 10
n = 10
p = 0.5
q = 0.5
G = nx.partial_duplication_graph(N, n, p, q)
assert len(G) == n
def test_invalid_initial_size(self):
with pytest.raises(nx.NetworkXError):
N = 5
n = 10
p = 0.5
q = 0.5
G = nx.partial_duplication_graph(N, n, p, q)
def test_invalid_probabilities(self):
N = 1
n = 1
for p, q in [(0.5, 2), (0.5, -1), (2, 0.5), (-1, 0.5)]:
args = (N, n, p, q)
pytest.raises(nx.NetworkXError, nx.partial_duplication_graph, *args)
def test_create_using(self):
class DummyGraph(nx.Graph):
pass
class DummyDiGraph(nx.DiGraph):
pass
G = nx.partial_duplication_graph(10, 5, 0.5, 0.5, create_using=DummyGraph)
assert isinstance(G, DummyGraph)
with pytest.raises(nx.NetworkXError, match="create_using must not be directed"):
nx.partial_duplication_graph(10, 5, 0.5, 0.5, create_using=DummyDiGraph)

View File

@ -0,0 +1,39 @@
"""
ego graph
---------
"""
import networkx as nx
from networkx.utils import edges_equal, nodes_equal
class TestGeneratorEgo:
def test_ego(self):
G = nx.star_graph(3)
H = nx.ego_graph(G, 0)
assert nx.is_isomorphic(G, H)
G.add_edge(1, 11)
G.add_edge(2, 22)
G.add_edge(3, 33)
H = nx.ego_graph(G, 0)
assert nx.is_isomorphic(nx.star_graph(3), H)
G = nx.path_graph(3)
H = nx.ego_graph(G, 0)
assert edges_equal(H.edges(), [(0, 1)])
H = nx.ego_graph(G, 0, undirected=True)
assert edges_equal(H.edges(), [(0, 1)])
H = nx.ego_graph(G, 0, center=False)
assert edges_equal(H.edges(), [])
def test_ego_distance(self):
G = nx.Graph()
G.add_edge(0, 1, weight=2, distance=1)
G.add_edge(1, 2, weight=2, distance=2)
G.add_edge(2, 3, weight=2, distance=1)
assert nodes_equal(nx.ego_graph(G, 0, radius=3).nodes(), [0, 1, 2, 3])
eg = nx.ego_graph(G, 0, radius=3, distance="weight")
assert nodes_equal(eg.nodes(), [0, 1])
eg = nx.ego_graph(G, 0, radius=3, distance="weight", undirected=True)
assert nodes_equal(eg.nodes(), [0, 1])
eg = nx.ego_graph(G, 0, radius=3, distance="distance")
assert nodes_equal(eg.nodes(), [0, 1, 2])

View File

@ -0,0 +1,162 @@
"""Unit tests for the :mod:`networkx.generators.expanders` module."""
import pytest
import networkx as nx
@pytest.mark.parametrize("n", (2, 3, 5, 6, 10))
def test_margulis_gabber_galil_graph_properties(n):
g = nx.margulis_gabber_galil_graph(n)
assert g.number_of_nodes() == n * n
for node in g:
assert g.degree(node) == 8
assert len(node) == 2
for i in node:
assert int(i) == i
assert 0 <= i < n
@pytest.mark.parametrize("n", (2, 3, 5, 6, 10))
def test_margulis_gabber_galil_graph_eigvals(n):
np = pytest.importorskip("numpy")
sp = pytest.importorskip("scipy")
g = nx.margulis_gabber_galil_graph(n)
# Eigenvalues are already sorted using the scipy eigvalsh,
# but the implementation in numpy does not guarantee order.
w = sorted(sp.linalg.eigvalsh(nx.adjacency_matrix(g).toarray()))
assert w[-2] < 5 * np.sqrt(2)
@pytest.mark.parametrize("p", (3, 5, 7, 11)) # Primes
def test_chordal_cycle_graph(p):
"""Test for the :func:`networkx.chordal_cycle_graph` function."""
G = nx.chordal_cycle_graph(p)
assert len(G) == p
# TODO The second largest eigenvalue should be smaller than a constant,
# independent of the number of nodes in the graph:
#
# eigs = sorted(sp.linalg.eigvalsh(nx.adjacency_matrix(G).toarray()))
# assert_less(eigs[-2], ...)
#
@pytest.mark.parametrize("p", (3, 5, 7, 11, 13)) # Primes
def test_paley_graph(p):
"""Test for the :func:`networkx.paley_graph` function."""
G = nx.paley_graph(p)
# G has p nodes
assert len(G) == p
# G is (p-1)/2-regular
in_degrees = {G.in_degree(node) for node in G.nodes}
out_degrees = {G.out_degree(node) for node in G.nodes}
assert len(in_degrees) == 1 and in_degrees.pop() == (p - 1) // 2
assert len(out_degrees) == 1 and out_degrees.pop() == (p - 1) // 2
# If p = 1 mod 4, -1 is a square mod 4 and therefore the
# edge in the Paley graph are symmetric.
if p % 4 == 1:
for u, v in G.edges:
assert (v, u) in G.edges
@pytest.mark.parametrize("d, n", [(2, 7), (4, 10), (4, 16)])
def test_maybe_regular_expander(d, n):
pytest.importorskip("numpy")
G = nx.maybe_regular_expander(n, d)
assert len(G) == n, "Should have n nodes"
assert len(G.edges) == n * d / 2, "Should have n*d/2 edges"
assert nx.is_k_regular(G, d), "Should be d-regular"
@pytest.mark.parametrize("n", (3, 5, 6, 10))
def test_is_regular_expander(n):
pytest.importorskip("numpy")
pytest.importorskip("scipy")
G = nx.complete_graph(n)
assert nx.is_regular_expander(G) == True, "Should be a regular expander"
@pytest.mark.parametrize("d, n", [(2, 7), (4, 10), (4, 16)])
def test_random_regular_expander(d, n):
pytest.importorskip("numpy")
pytest.importorskip("scipy")
G = nx.random_regular_expander_graph(n, d)
assert len(G) == n, "Should have n nodes"
assert len(G.edges) == n * d / 2, "Should have n*d/2 edges"
assert nx.is_k_regular(G, d), "Should be d-regular"
assert nx.is_regular_expander(G) == True, "Should be a regular expander"
def test_random_regular_expander_explicit_construction():
pytest.importorskip("numpy")
pytest.importorskip("scipy")
G = nx.random_regular_expander_graph(d=4, n=5)
assert len(G) == 5 and len(G.edges) == 10, "Should be a complete graph"
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph, nx.MultiDiGraph))
def test_margulis_gabber_galil_graph_badinput(graph_type):
with pytest.raises(
nx.NetworkXError, match="`create_using` must be an undirected multigraph"
):
nx.margulis_gabber_galil_graph(3, create_using=graph_type)
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph, nx.MultiDiGraph))
def test_chordal_cycle_graph_badinput(graph_type):
with pytest.raises(
nx.NetworkXError, match="`create_using` must be an undirected multigraph"
):
nx.chordal_cycle_graph(3, create_using=graph_type)
def test_paley_graph_badinput():
with pytest.raises(
nx.NetworkXError, match="`create_using` cannot be a multigraph."
):
nx.paley_graph(3, create_using=nx.MultiGraph)
def test_maybe_regular_expander_badinput():
pytest.importorskip("numpy")
pytest.importorskip("scipy")
with pytest.raises(nx.NetworkXError, match="n must be a positive integer"):
nx.maybe_regular_expander(n=-1, d=2)
with pytest.raises(nx.NetworkXError, match="d must be greater than or equal to 2"):
nx.maybe_regular_expander(n=10, d=0)
with pytest.raises(nx.NetworkXError, match="Need n-1>= d to have room"):
nx.maybe_regular_expander(n=5, d=6)
def test_is_regular_expander_badinput():
pytest.importorskip("numpy")
pytest.importorskip("scipy")
with pytest.raises(nx.NetworkXError, match="epsilon must be non negative"):
nx.is_regular_expander(nx.Graph(), epsilon=-1)
def test_random_regular_expander_badinput():
pytest.importorskip("numpy")
pytest.importorskip("scipy")
with pytest.raises(nx.NetworkXError, match="n must be a positive integer"):
nx.random_regular_expander_graph(n=-1, d=2)
with pytest.raises(nx.NetworkXError, match="d must be greater than or equal to 2"):
nx.random_regular_expander_graph(n=10, d=0)
with pytest.raises(nx.NetworkXError, match="Need n-1>= d to have room"):
nx.random_regular_expander_graph(n=5, d=6)
with pytest.raises(nx.NetworkXError, match="epsilon must be non negative"):
nx.random_regular_expander_graph(n=4, d=2, epsilon=-1)

View File

@ -0,0 +1,488 @@
import math
import random
from itertools import combinations
import pytest
import networkx as nx
def l1dist(x, y):
return sum(abs(a - b) for a, b in zip(x, y))
class TestRandomGeometricGraph:
"""Unit tests for :func:`~networkx.random_geometric_graph`"""
def test_number_of_nodes(self):
G = nx.random_geometric_graph(50, 0.25, seed=42)
assert len(G) == 50
G = nx.random_geometric_graph(range(50), 0.25, seed=42)
assert len(G) == 50
def test_distances(self):
"""Tests that pairs of vertices adjacent if and only if they are
within the prescribed radius.
"""
# Use the Euclidean metric, the default according to the
# documentation.
G = nx.random_geometric_graph(50, 0.25)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
# Nonadjacent vertices must be at greater distance.
else:
assert not math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_p(self):
"""Tests for providing an alternate distance metric to the generator."""
# Use the L1 metric.
G = nx.random_geometric_graph(50, 0.25, p=1)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert l1dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
# Nonadjacent vertices must be at greater distance.
else:
assert not l1dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_node_names(self):
"""Tests using values other than sequential numbers as node IDs."""
import string
nodes = list(string.ascii_lowercase)
G = nx.random_geometric_graph(nodes, 0.25)
assert len(G) == len(nodes)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
# Nonadjacent vertices must be at greater distance.
else:
assert not math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_pos_name(self):
G = nx.random_geometric_graph(50, 0.25, seed=42, pos_name="coords")
assert all(len(d["coords"]) == 2 for n, d in G.nodes.items())
class TestSoftRandomGeometricGraph:
"""Unit tests for :func:`~networkx.soft_random_geometric_graph`"""
def test_number_of_nodes(self):
G = nx.soft_random_geometric_graph(50, 0.25, seed=42)
assert len(G) == 50
G = nx.soft_random_geometric_graph(range(50), 0.25, seed=42)
assert len(G) == 50
def test_distances(self):
"""Tests that pairs of vertices adjacent if and only if they are
within the prescribed radius.
"""
# Use the Euclidean metric, the default according to the
# documentation.
G = nx.soft_random_geometric_graph(50, 0.25)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_p(self):
"""Tests for providing an alternate distance metric to the generator."""
# Use the L1 metric.
def dist(x, y):
return sum(abs(a - b) for a, b in zip(x, y))
G = nx.soft_random_geometric_graph(50, 0.25, p=1)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_node_names(self):
"""Tests using values other than sequential numbers as node IDs."""
import string
nodes = list(string.ascii_lowercase)
G = nx.soft_random_geometric_graph(nodes, 0.25)
assert len(G) == len(nodes)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_p_dist_default(self):
"""Tests default p_dict = 0.5 returns graph with edge count <= RGG with
same n, radius, dim and positions
"""
nodes = 50
dim = 2
pos = {v: [random.random() for i in range(dim)] for v in range(nodes)}
RGG = nx.random_geometric_graph(50, 0.25, pos=pos)
SRGG = nx.soft_random_geometric_graph(50, 0.25, pos=pos)
assert len(SRGG.edges()) <= len(RGG.edges())
def test_p_dist_zero(self):
"""Tests if p_dict = 0 returns disconnected graph with 0 edges"""
def p_dist(dist):
return 0
G = nx.soft_random_geometric_graph(50, 0.25, p_dist=p_dist)
assert len(G.edges) == 0
def test_pos_name(self):
G = nx.soft_random_geometric_graph(50, 0.25, seed=42, pos_name="coords")
assert all(len(d["coords"]) == 2 for n, d in G.nodes.items())
def join(G, u, v, theta, alpha, metric):
"""Returns ``True`` if and only if the nodes whose attributes are
``du`` and ``dv`` should be joined, according to the threshold
condition for geographical threshold graphs.
``G`` is an undirected NetworkX graph, and ``u`` and ``v`` are nodes
in that graph. The nodes must have node attributes ``'pos'`` and
``'weight'``.
``metric`` is a distance metric.
"""
du, dv = G.nodes[u], G.nodes[v]
u_pos, v_pos = du["pos"], dv["pos"]
u_weight, v_weight = du["weight"], dv["weight"]
return (u_weight + v_weight) * metric(u_pos, v_pos) ** alpha >= theta
class TestGeographicalThresholdGraph:
"""Unit tests for :func:`~networkx.geographical_threshold_graph`"""
def test_number_of_nodes(self):
G = nx.geographical_threshold_graph(50, 100, seed=42)
assert len(G) == 50
G = nx.geographical_threshold_graph(range(50), 100, seed=42)
assert len(G) == 50
def test_distances(self):
"""Tests that pairs of vertices adjacent if and only if their
distances meet the given threshold.
"""
# Use the Euclidean metric and alpha = -2
# the default according to the documentation.
G = nx.geographical_threshold_graph(50, 10)
for u, v in combinations(G, 2):
# Adjacent vertices must exceed the threshold.
if v in G[u]:
assert join(G, u, v, 10, -2, math.dist)
# Nonadjacent vertices must not exceed the threshold.
else:
assert not join(G, u, v, 10, -2, math.dist)
def test_metric(self):
"""Tests for providing an alternate distance metric to the generator."""
# Use the L1 metric.
G = nx.geographical_threshold_graph(50, 10, metric=l1dist)
for u, v in combinations(G, 2):
# Adjacent vertices must exceed the threshold.
if v in G[u]:
assert join(G, u, v, 10, -2, l1dist)
# Nonadjacent vertices must not exceed the threshold.
else:
assert not join(G, u, v, 10, -2, l1dist)
def test_p_dist_zero(self):
"""Tests if p_dict = 0 returns disconnected graph with 0 edges"""
def p_dist(dist):
return 0
G = nx.geographical_threshold_graph(50, 1, p_dist=p_dist)
assert len(G.edges) == 0
def test_pos_weight_name(self):
gtg = nx.geographical_threshold_graph
G = gtg(50, 100, seed=42, pos_name="coords", weight_name="wt")
assert all(len(d["coords"]) == 2 for n, d in G.nodes.items())
assert all(d["wt"] > 0 for n, d in G.nodes.items())
class TestWaxmanGraph:
"""Unit tests for the :func:`~networkx.waxman_graph` function."""
def test_number_of_nodes_1(self):
G = nx.waxman_graph(50, 0.5, 0.1, seed=42)
assert len(G) == 50
G = nx.waxman_graph(range(50), 0.5, 0.1, seed=42)
assert len(G) == 50
def test_number_of_nodes_2(self):
G = nx.waxman_graph(50, 0.5, 0.1, L=1)
assert len(G) == 50
G = nx.waxman_graph(range(50), 0.5, 0.1, L=1)
assert len(G) == 50
def test_metric(self):
"""Tests for providing an alternate distance metric to the generator."""
# Use the L1 metric.
G = nx.waxman_graph(50, 0.5, 0.1, metric=l1dist)
assert len(G) == 50
def test_pos_name(self):
G = nx.waxman_graph(50, 0.5, 0.1, seed=42, pos_name="coords")
assert all(len(d["coords"]) == 2 for n, d in G.nodes.items())
class TestNavigableSmallWorldGraph:
def test_navigable_small_world(self):
G = nx.navigable_small_world_graph(5, p=1, q=0, seed=42)
gg = nx.grid_2d_graph(5, 5).to_directed()
assert nx.is_isomorphic(G, gg)
G = nx.navigable_small_world_graph(5, p=1, q=0, dim=3)
gg = nx.grid_graph([5, 5, 5]).to_directed()
assert nx.is_isomorphic(G, gg)
G = nx.navigable_small_world_graph(5, p=1, q=0, dim=1)
gg = nx.grid_graph([5]).to_directed()
assert nx.is_isomorphic(G, gg)
def test_invalid_diameter_value(self):
with pytest.raises(nx.NetworkXException, match=".*p must be >= 1"):
nx.navigable_small_world_graph(5, p=0, q=0, dim=1)
def test_invalid_long_range_connections_value(self):
with pytest.raises(nx.NetworkXException, match=".*q must be >= 0"):
nx.navigable_small_world_graph(5, p=1, q=-1, dim=1)
def test_invalid_exponent_for_decaying_probability_value(self):
with pytest.raises(nx.NetworkXException, match=".*r must be >= 0"):
nx.navigable_small_world_graph(5, p=1, q=0, r=-1, dim=1)
def test_r_between_0_and_1(self):
"""Smoke test for radius in range [0, 1]"""
# q=0 means no long-range connections
G = nx.navigable_small_world_graph(3, p=1, q=0, r=0.5, dim=2, seed=42)
expected = nx.grid_2d_graph(3, 3, create_using=nx.DiGraph)
assert nx.utils.graphs_equal(G, expected)
@pytest.mark.parametrize("seed", range(2478, 2578, 10))
def test_r_general_scaling(self, seed):
"""The probability of adding a long-range edge scales with `1 / dist**r`,
so a navigable_small_world graph created with r < 1 should generally
result in more edges than a navigable_small_world graph with r >= 1
(for 0 < q << n).
N.B. this is probabilistic, so this test may not hold for all seeds."""
G1 = nx.navigable_small_world_graph(7, q=3, r=0.5, seed=seed)
G2 = nx.navigable_small_world_graph(7, q=3, r=1, seed=seed)
G3 = nx.navigable_small_world_graph(7, q=3, r=2, seed=seed)
assert G1.number_of_edges() > G2.number_of_edges()
assert G2.number_of_edges() > G3.number_of_edges()
class TestThresholdedRandomGeometricGraph:
"""Unit tests for :func:`~networkx.thresholded_random_geometric_graph`"""
def test_number_of_nodes(self):
G = nx.thresholded_random_geometric_graph(50, 0.2, 0.1, seed=42)
assert len(G) == 50
G = nx.thresholded_random_geometric_graph(range(50), 0.2, 0.1, seed=42)
assert len(G) == 50
def test_distances(self):
"""Tests that pairs of vertices adjacent if and only if they are
within the prescribed radius.
"""
# Use the Euclidean metric, the default according to the
# documentation.
G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, seed=42)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_p(self):
"""Tests for providing an alternate distance metric to the generator."""
# Use the L1 metric.
def dist(x, y):
return sum(abs(a - b) for a, b in zip(x, y))
G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, p=1, seed=42)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_node_names(self):
"""Tests using values other than sequential numbers as node IDs."""
import string
nodes = list(string.ascii_lowercase)
G = nx.thresholded_random_geometric_graph(nodes, 0.25, 0.1, seed=42)
assert len(G) == len(nodes)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert math.dist(G.nodes[u]["pos"], G.nodes[v]["pos"]) <= 0.25
def test_theta(self):
"""Tests that pairs of vertices adjacent if and only if their sum
weights exceeds the threshold parameter theta.
"""
G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, seed=42)
for u, v in combinations(G, 2):
# Adjacent vertices must be within the given distance.
if v in G[u]:
assert (G.nodes[u]["weight"] + G.nodes[v]["weight"]) >= 0.1
def test_pos_name(self):
trgg = nx.thresholded_random_geometric_graph
G = trgg(50, 0.25, 0.1, seed=42, pos_name="p", weight_name="wt")
assert all(len(d["p"]) == 2 for n, d in G.nodes.items())
assert all(d["wt"] > 0 for n, d in G.nodes.items())
def test_geometric_edges_pos_attribute():
G = nx.Graph()
G.add_nodes_from(
[
(0, {"position": (0, 0)}),
(1, {"position": (0, 1)}),
(2, {"position": (1, 0)}),
]
)
expected_edges = [(0, 1), (0, 2)]
assert expected_edges == nx.geometric_edges(G, radius=1, pos_name="position")
def test_geometric_edges_raises_no_pos():
G = nx.path_graph(3)
msg = "all nodes. must have a '"
with pytest.raises(nx.NetworkXError, match=msg):
nx.geometric_edges(G, radius=1)
def test_number_of_nodes_S1():
G = nx.geometric_soft_configuration_graph(
beta=1.5, n=100, gamma=2.7, mean_degree=10, seed=42
)
assert len(G) == 100
def test_set_attributes_S1():
G = nx.geometric_soft_configuration_graph(
beta=1.5, n=100, gamma=2.7, mean_degree=10, seed=42
)
kappas = nx.get_node_attributes(G, "kappa")
assert len(kappas) == 100
thetas = nx.get_node_attributes(G, "theta")
assert len(thetas) == 100
radii = nx.get_node_attributes(G, "radius")
assert len(radii) == 100
def test_mean_kappas_mean_degree_S1():
G = nx.geometric_soft_configuration_graph(
beta=2.5, n=50, gamma=2.7, mean_degree=10, seed=8023
)
kappas = nx.get_node_attributes(G, "kappa")
mean_kappas = sum(kappas.values()) / len(kappas)
assert math.fabs(mean_kappas - 10) < 0.5
degrees = dict(G.degree())
mean_degree = sum(degrees.values()) / len(degrees)
assert math.fabs(mean_degree - 10) < 1
def test_dict_kappas_S1():
kappas = {i: 10 for i in range(1000)}
G = nx.geometric_soft_configuration_graph(beta=1, kappas=kappas)
assert len(G) == 1000
kappas = nx.get_node_attributes(G, "kappa")
assert all(kappa == 10 for kappa in kappas.values())
def test_beta_clustering_S1():
G1 = nx.geometric_soft_configuration_graph(
beta=1.5, n=100, gamma=3.5, mean_degree=10, seed=42
)
G2 = nx.geometric_soft_configuration_graph(
beta=3.0, n=100, gamma=3.5, mean_degree=10, seed=42
)
assert nx.average_clustering(G1) < nx.average_clustering(G2)
def test_wrong_parameters_S1():
with pytest.raises(
nx.NetworkXError,
match="Please provide either kappas, or all 3 of: n, gamma and mean_degree.",
):
G = nx.geometric_soft_configuration_graph(
beta=1.5, gamma=3.5, mean_degree=10, seed=42
)
with pytest.raises(
nx.NetworkXError,
match="When kappas is input, n, gamma and mean_degree must not be.",
):
kappas = {i: 10 for i in range(1000)}
G = nx.geometric_soft_configuration_graph(
beta=1.5, kappas=kappas, gamma=2.3, seed=42
)
with pytest.raises(
nx.NetworkXError,
match="Please provide either kappas, or all 3 of: n, gamma and mean_degree.",
):
G = nx.geometric_soft_configuration_graph(beta=1.5, seed=42)
def test_negative_beta_S1():
with pytest.raises(
nx.NetworkXError, match="The parameter beta cannot be smaller or equal to 0."
):
G = nx.geometric_soft_configuration_graph(
beta=-1, n=100, gamma=2.3, mean_degree=10, seed=42
)
def test_non_zero_clustering_beta_lower_one_S1():
G = nx.geometric_soft_configuration_graph(
beta=0.5, n=100, gamma=3.5, mean_degree=10, seed=42
)
assert nx.average_clustering(G) > 0
def test_mean_degree_influence_on_connectivity_S1():
low_mean_degree = 2
high_mean_degree = 20
G_low = nx.geometric_soft_configuration_graph(
beta=1.2, n=100, gamma=2.7, mean_degree=low_mean_degree, seed=42
)
G_high = nx.geometric_soft_configuration_graph(
beta=1.2, n=100, gamma=2.7, mean_degree=high_mean_degree, seed=42
)
assert nx.number_connected_components(G_low) > nx.number_connected_components(
G_high
)
def test_compare_mean_kappas_different_gammas_S1():
G1 = nx.geometric_soft_configuration_graph(
beta=1.5, n=20, gamma=2.7, mean_degree=5, seed=42
)
G2 = nx.geometric_soft_configuration_graph(
beta=1.5, n=20, gamma=3.5, mean_degree=5, seed=42
)
kappas1 = nx.get_node_attributes(G1, "kappa")
mean_kappas1 = sum(kappas1.values()) / len(kappas1)
kappas2 = nx.get_node_attributes(G2, "kappa")
mean_kappas2 = sum(kappas2.values()) / len(kappas2)
assert math.fabs(mean_kappas1 - mean_kappas2) < 1

View File

@ -0,0 +1,133 @@
"""Unit tests for the :mod:`networkx.generators.harary_graph` module."""
import pytest
import networkx as nx
from networkx.algorithms.isomorphism.isomorph import is_isomorphic
from networkx.generators.harary_graph import hkn_harary_graph, hnm_harary_graph
class TestHararyGraph:
"""
Suppose n nodes, m >= n-1 edges, d = 2m // n, r = 2m % n
"""
def test_hnm_harary_graph(self):
# When d is even and r = 0, the hnm_harary_graph(n,m) is
# the circulant_graph(n, list(range(1,d/2+1)))
for n, m in [(5, 5), (6, 12), (7, 14)]:
G1 = hnm_harary_graph(n, m)
d = 2 * m // n
G2 = nx.circulant_graph(n, list(range(1, d // 2 + 1)))
assert is_isomorphic(G1, G2)
# When d is even and r > 0, the hnm_harary_graph(n,m) is
# the circulant_graph(n, list(range(1,d/2+1)))
# with r edges added arbitrarily
for n, m in [(5, 7), (6, 13), (7, 16)]:
G1 = hnm_harary_graph(n, m)
d = 2 * m // n
G2 = nx.circulant_graph(n, list(range(1, d // 2 + 1)))
assert set(G2.edges) < set(G1.edges)
assert G1.number_of_edges() == m
# When d is odd and n is even and r = 0, the hnm_harary_graph(n,m)
# is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2])
for n, m in [(6, 9), (8, 12), (10, 15)]:
G1 = hnm_harary_graph(n, m)
d = 2 * m // n
L = list(range(1, (d + 1) // 2))
L.append(n // 2)
G2 = nx.circulant_graph(n, L)
assert is_isomorphic(G1, G2)
# When d is odd and n is even and r > 0, the hnm_harary_graph(n,m)
# is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2])
# with r edges added arbitrarily
for n, m in [(6, 10), (8, 13), (10, 17)]:
G1 = hnm_harary_graph(n, m)
d = 2 * m // n
L = list(range(1, (d + 1) // 2))
L.append(n // 2)
G2 = nx.circulant_graph(n, L)
assert set(G2.edges) < set(G1.edges)
assert G1.number_of_edges() == m
# When d is odd and n is odd, the hnm_harary_graph(n,m) is
# the circulant_graph(n, list(range(1,(d+1)/2))
# with m - n*(d-1)/2 edges added arbitrarily
for n, m in [(5, 4), (7, 12), (9, 14)]:
G1 = hnm_harary_graph(n, m)
d = 2 * m // n
L = list(range(1, (d + 1) // 2))
G2 = nx.circulant_graph(n, L)
assert set(G2.edges) < set(G1.edges)
assert G1.number_of_edges() == m
# Raise NetworkXError if n<1
n = 0
m = 0
pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m)
# Raise NetworkXError if m < n-1
n = 6
m = 4
pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m)
# Raise NetworkXError if m > n(n-1)/2
n = 6
m = 16
pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m)
"""
Suppose connectivity k, number of nodes n
"""
def test_hkn_harary_graph(self):
# When k == 1, the hkn_harary_graph(k,n) is
# the path_graph(n)
for k, n in [(1, 6), (1, 7)]:
G1 = hkn_harary_graph(k, n)
G2 = nx.path_graph(n)
assert is_isomorphic(G1, G2)
# When k is even, the hkn_harary_graph(k,n) is
# the circulant_graph(n, list(range(1,k/2+1)))
for k, n in [(2, 6), (2, 7), (4, 6), (4, 7)]:
G1 = hkn_harary_graph(k, n)
G2 = nx.circulant_graph(n, list(range(1, k // 2 + 1)))
assert is_isomorphic(G1, G2)
# When k is odd and n is even, the hkn_harary_graph(k,n) is
# the circulant_graph(n, list(range(1,(k+1)/2)) plus [n/2])
for k, n in [(3, 6), (5, 8), (7, 10)]:
G1 = hkn_harary_graph(k, n)
L = list(range(1, (k + 1) // 2))
L.append(n // 2)
G2 = nx.circulant_graph(n, L)
assert is_isomorphic(G1, G2)
# When k is odd and n is odd, the hkn_harary_graph(k,n) is
# the circulant_graph(n, list(range(1,(k+1)/2))) with
# n//2+1 edges added between node i and node i+n//2+1
for k, n in [(3, 5), (5, 9), (7, 11)]:
G1 = hkn_harary_graph(k, n)
G2 = nx.circulant_graph(n, list(range(1, (k + 1) // 2)))
eSet1 = set(G1.edges)
eSet2 = set(G2.edges)
eSet3 = set()
half = n // 2
for i in range(half + 1):
# add half+1 edges between i and i+half
eSet3.add((i, (i + half) % n))
assert eSet1 == eSet2 | eSet3
# Raise NetworkXError if k<1
k = 0
n = 0
pytest.raises(nx.NetworkXError, hkn_harary_graph, k, n)
# Raise NetworkXError if n<k+1
k = 6
n = 6
pytest.raises(nx.NetworkXError, hkn_harary_graph, k, n)

View File

@ -0,0 +1,176 @@
from pytest import approx
from networkx import is_connected, neighbors
from networkx.generators.internet_as_graphs import random_internet_as_graph
class TestInternetASTopology:
@classmethod
def setup_class(cls):
cls.n = 1000
cls.seed = 42
cls.G = random_internet_as_graph(cls.n, cls.seed)
cls.T = []
cls.M = []
cls.C = []
cls.CP = []
cls.customers = {}
cls.providers = {}
for i in cls.G.nodes():
if cls.G.nodes[i]["type"] == "T":
cls.T.append(i)
elif cls.G.nodes[i]["type"] == "M":
cls.M.append(i)
elif cls.G.nodes[i]["type"] == "C":
cls.C.append(i)
elif cls.G.nodes[i]["type"] == "CP":
cls.CP.append(i)
else:
raise ValueError("Inconsistent data in the graph node attributes")
cls.set_customers(i)
cls.set_providers(i)
@classmethod
def set_customers(cls, i):
if i not in cls.customers:
cls.customers[i] = set()
for j in neighbors(cls.G, i):
e = cls.G.edges[(i, j)]
if e["type"] == "transit":
customer = int(e["customer"])
if j == customer:
cls.set_customers(j)
cls.customers[i] = cls.customers[i].union(cls.customers[j])
cls.customers[i].add(j)
elif i != customer:
raise ValueError(
"Inconsistent data in the graph edge attributes"
)
@classmethod
def set_providers(cls, i):
if i not in cls.providers:
cls.providers[i] = set()
for j in neighbors(cls.G, i):
e = cls.G.edges[(i, j)]
if e["type"] == "transit":
customer = int(e["customer"])
if i == customer:
cls.set_providers(j)
cls.providers[i] = cls.providers[i].union(cls.providers[j])
cls.providers[i].add(j)
elif j != customer:
raise ValueError(
"Inconsistent data in the graph edge attributes"
)
def test_wrong_input(self):
G = random_internet_as_graph(0)
assert len(G.nodes()) == 0
G = random_internet_as_graph(-1)
assert len(G.nodes()) == 0
G = random_internet_as_graph(1)
assert len(G.nodes()) == 1
def test_node_numbers(self):
assert len(self.G.nodes()) == self.n
assert len(self.T) < 7
assert len(self.M) == round(self.n * 0.15)
assert len(self.CP) == round(self.n * 0.05)
numb = self.n - len(self.T) - len(self.M) - len(self.CP)
assert len(self.C) == numb
def test_connectivity(self):
assert is_connected(self.G)
def test_relationships(self):
# T nodes are not customers of anyone
for i in self.T:
assert len(self.providers[i]) == 0
# C nodes are not providers of anyone
for i in self.C:
assert len(self.customers[i]) == 0
# CP nodes are not providers of anyone
for i in self.CP:
assert len(self.customers[i]) == 0
# test whether there is a customer-provider loop
for i in self.G.nodes():
assert len(self.customers[i].intersection(self.providers[i])) == 0
# test whether there is a peering with a customer or provider
for i, j in self.G.edges():
if self.G.edges[(i, j)]["type"] == "peer":
assert j not in self.customers[i]
assert i not in self.customers[j]
assert j not in self.providers[i]
assert i not in self.providers[j]
def test_degree_values(self):
d_m = 0 # multihoming degree for M nodes
d_cp = 0 # multihoming degree for CP nodes
d_c = 0 # multihoming degree for C nodes
p_m_m = 0 # avg number of peering edges between M and M
p_cp_m = 0 # avg number of peering edges between CP and M
p_cp_cp = 0 # avg number of peering edges between CP and CP
t_m = 0 # probability M's provider is T
t_cp = 0 # probability CP's provider is T
t_c = 0 # probability C's provider is T
for i, j in self.G.edges():
e = self.G.edges[(i, j)]
if e["type"] == "transit":
cust = int(e["customer"])
if i == cust:
prov = j
elif j == cust:
prov = i
else:
raise ValueError("Inconsistent data in the graph edge attributes")
if cust in self.M:
d_m += 1
if self.G.nodes[prov]["type"] == "T":
t_m += 1
elif cust in self.C:
d_c += 1
if self.G.nodes[prov]["type"] == "T":
t_c += 1
elif cust in self.CP:
d_cp += 1
if self.G.nodes[prov]["type"] == "T":
t_cp += 1
else:
raise ValueError("Inconsistent data in the graph edge attributes")
elif e["type"] == "peer":
if self.G.nodes[i]["type"] == "M" and self.G.nodes[j]["type"] == "M":
p_m_m += 1
if self.G.nodes[i]["type"] == "CP" and self.G.nodes[j]["type"] == "CP":
p_cp_cp += 1
if (
self.G.nodes[i]["type"] == "M"
and self.G.nodes[j]["type"] == "CP"
or self.G.nodes[i]["type"] == "CP"
and self.G.nodes[j]["type"] == "M"
):
p_cp_m += 1
else:
raise ValueError("Unexpected data in the graph edge attributes")
assert d_m / len(self.M) == approx((2 + (2.5 * self.n) / 10000), abs=1e-0)
assert d_cp / len(self.CP) == approx((2 + (1.5 * self.n) / 10000), abs=1e-0)
assert d_c / len(self.C) == approx((1 + (5 * self.n) / 100000), abs=1e-0)
assert p_m_m / len(self.M) == approx((1 + (2 * self.n) / 10000), abs=1e-0)
assert p_cp_m / len(self.CP) == approx((0.2 + (2 * self.n) / 10000), abs=1e-0)
assert p_cp_cp / len(self.CP) == approx(
(0.05 + (2 * self.n) / 100000), abs=1e-0
)
assert t_m / d_m == approx(0.375, abs=1e-1)
assert t_cp / d_cp == approx(0.375, abs=1e-1)
assert t_c / d_c == approx(0.125, abs=1e-1)

View File

@ -0,0 +1,28 @@
import pytest
import networkx as nx
class TestIntersectionGraph:
def test_random_intersection_graph(self):
G = nx.uniform_random_intersection_graph(10, 5, 0.5)
assert len(G) == 10
def test_k_random_intersection_graph(self):
G = nx.k_random_intersection_graph(10, 5, 2)
assert len(G) == 10
def test_k_random_intersection_graph_seeded(self):
G = nx.k_random_intersection_graph(10, 5, 2, seed=1234)
assert len(G) == 10
def test_general_random_intersection_graph(self):
G = nx.general_random_intersection_graph(10, 5, [0.1, 0.2, 0.2, 0.1, 0.1])
assert len(G) == 10
pytest.raises(
ValueError,
nx.general_random_intersection_graph,
10,
5,
[0.1, 0.2, 0.2, 0.1],
)

View File

@ -0,0 +1,144 @@
"""Unit tests for the :mod:`networkx.generators.interval_graph` module."""
import math
import pytest
import networkx as nx
from networkx.generators.interval_graph import interval_graph
from networkx.utils import edges_equal
class TestIntervalGraph:
"""Unit tests for :func:`networkx.generators.interval_graph.interval_graph`"""
def test_empty(self):
"""Tests for trivial case of empty input"""
assert len(interval_graph([])) == 0
def test_interval_graph_check_invalid(self):
"""Tests for conditions that raise Exceptions"""
invalids_having_none = [None, (1, 2)]
with pytest.raises(TypeError):
interval_graph(invalids_having_none)
invalids_having_set = [{1, 2}]
with pytest.raises(TypeError):
interval_graph(invalids_having_set)
invalids_having_seq_but_not_length2 = [(1, 2, 3)]
with pytest.raises(TypeError):
interval_graph(invalids_having_seq_but_not_length2)
invalids_interval = [[3, 2]]
with pytest.raises(ValueError):
interval_graph(invalids_interval)
def test_interval_graph_0(self):
intervals = [(1, 2), (1, 3)]
expected_graph = nx.Graph()
expected_graph.add_edge(*intervals)
actual_g = interval_graph(intervals)
assert set(actual_g.nodes) == set(expected_graph.nodes)
assert edges_equal(expected_graph, actual_g)
def test_interval_graph_1(self):
intervals = [(1, 2), (2, 3), (3, 4), (1, 4)]
expected_graph = nx.Graph()
expected_graph.add_nodes_from(intervals)
e1 = ((1, 4), (1, 2))
e2 = ((1, 4), (2, 3))
e3 = ((1, 4), (3, 4))
e4 = ((3, 4), (2, 3))
e5 = ((1, 2), (2, 3))
expected_graph.add_edges_from([e1, e2, e3, e4, e5])
actual_g = interval_graph(intervals)
assert set(actual_g.nodes) == set(expected_graph.nodes)
assert edges_equal(expected_graph, actual_g)
def test_interval_graph_2(self):
intervals = [(1, 2), [3, 5], [6, 8], (9, 10)]
expected_graph = nx.Graph()
expected_graph.add_nodes_from([(1, 2), (3, 5), (6, 8), (9, 10)])
actual_g = interval_graph(intervals)
assert set(actual_g.nodes) == set(expected_graph.nodes)
assert edges_equal(expected_graph, actual_g)
def test_interval_graph_3(self):
intervals = [(1, 4), [3, 5], [2.5, 4]]
expected_graph = nx.Graph()
expected_graph.add_nodes_from([(1, 4), (3, 5), (2.5, 4)])
e1 = ((1, 4), (3, 5))
e2 = ((1, 4), (2.5, 4))
e3 = ((3, 5), (2.5, 4))
expected_graph.add_edges_from([e1, e2, e3])
actual_g = interval_graph(intervals)
assert set(actual_g.nodes) == set(expected_graph.nodes)
assert edges_equal(expected_graph, actual_g)
def test_interval_graph_4(self):
"""test all possible overlaps"""
intervals = [
(0, 2),
(-2, -1),
(-2, 0),
(-2, 1),
(-2, 2),
(-2, 3),
(0, 1),
(0, 2),
(0, 3),
(1, 2),
(1, 3),
(2, 3),
(3, 4),
]
expected_graph = nx.Graph()
expected_graph.add_nodes_from(intervals)
expected_nbrs = {
(-2, 0),
(-2, 1),
(-2, 2),
(-2, 3),
(0, 1),
(0, 2),
(0, 3),
(1, 2),
(1, 3),
(2, 3),
}
actual_g = nx.interval_graph(intervals)
actual_nbrs = nx.neighbors(actual_g, (0, 2))
assert set(actual_nbrs) == expected_nbrs
def test_interval_graph_5(self):
"""this test is to see that an interval supports infinite number"""
intervals = {(-math.inf, 0), (-1, -1), (0.5, 0.5), (1, 1), (1, math.inf)}
expected_graph = nx.Graph()
expected_graph.add_nodes_from(intervals)
e1 = ((-math.inf, 0), (-1, -1))
e2 = ((1, 1), (1, math.inf))
expected_graph.add_edges_from([e1, e2])
actual_g = interval_graph(intervals)
assert set(actual_g.nodes) == set(expected_graph.nodes)
assert edges_equal(expected_graph, actual_g)

View File

@ -0,0 +1,125 @@
import time
from networkx.algorithms.assortativity import degree_mixing_dict
from networkx.generators import gnm_random_graph, powerlaw_cluster_graph
from networkx.generators.joint_degree_seq import (
directed_joint_degree_graph,
is_valid_directed_joint_degree,
is_valid_joint_degree,
joint_degree_graph,
)
def test_is_valid_joint_degree():
"""Tests for conditions that invalidate a joint degree dict"""
# valid joint degree that satisfies all five conditions
joint_degrees = {
1: {4: 1},
2: {2: 2, 3: 2, 4: 2},
3: {2: 2, 4: 1},
4: {1: 1, 2: 2, 3: 1},
}
assert is_valid_joint_degree(joint_degrees)
# test condition 1
# joint_degrees_1[1][4] not integer
joint_degrees_1 = {
1: {4: 1.5},
2: {2: 2, 3: 2, 4: 2},
3: {2: 2, 4: 1},
4: {1: 1.5, 2: 2, 3: 1},
}
assert not is_valid_joint_degree(joint_degrees_1)
# test condition 2
# degree_count[2] = sum(joint_degrees_2[2][j)/2, is not an int
# degree_count[4] = sum(joint_degrees_2[4][j)/4, is not an int
joint_degrees_2 = {
1: {4: 1},
2: {2: 2, 3: 2, 4: 3},
3: {2: 2, 4: 1},
4: {1: 1, 2: 3, 3: 1},
}
assert not is_valid_joint_degree(joint_degrees_2)
# test conditions 3 and 4
# joint_degrees_3[1][4]>degree_count[1]*degree_count[4]
joint_degrees_3 = {
1: {4: 2},
2: {2: 2, 3: 2, 4: 2},
3: {2: 2, 4: 1},
4: {1: 2, 2: 2, 3: 1},
}
assert not is_valid_joint_degree(joint_degrees_3)
# test condition 5
# joint_degrees_5[1][1] not even
joint_degrees_5 = {1: {1: 9}}
assert not is_valid_joint_degree(joint_degrees_5)
def test_joint_degree_graph(ntimes=10):
for _ in range(ntimes):
seed = int(time.time())
n, m, p = 20, 10, 1
# generate random graph with model powerlaw_cluster and calculate
# its joint degree
g = powerlaw_cluster_graph(n, m, p, seed=seed)
joint_degrees_g = degree_mixing_dict(g, normalized=False)
# generate simple undirected graph with given joint degree
# joint_degrees_g
G = joint_degree_graph(joint_degrees_g)
joint_degrees_G = degree_mixing_dict(G, normalized=False)
# assert that the given joint degree is equal to the generated
# graph's joint degree
assert joint_degrees_g == joint_degrees_G
def test_is_valid_directed_joint_degree():
in_degrees = [0, 1, 1, 2]
out_degrees = [1, 1, 1, 1]
nkk = {1: {1: 2, 2: 2}}
assert is_valid_directed_joint_degree(in_degrees, out_degrees, nkk)
# not realizable, values are not integers.
nkk = {1: {1: 1.5, 2: 2.5}}
assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk)
# not realizable, number of edges between 1-2 are insufficient.
nkk = {1: {1: 2, 2: 1}}
assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk)
# not realizable, in/out degree sequences have different number of nodes.
out_degrees = [1, 1, 1]
nkk = {1: {1: 2, 2: 2}}
assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk)
# not realizable, degree sequences have fewer than required nodes.
in_degrees = [0, 1, 2]
assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk)
def test_directed_joint_degree_graph(n=15, m=100, ntimes=1000):
for _ in range(ntimes):
# generate gnm random graph and calculate its joint degree.
g = gnm_random_graph(n, m, None, directed=True)
# in-degree sequence of g as a list of integers.
in_degrees = list(dict(g.in_degree()).values())
# out-degree sequence of g as a list of integers.
out_degrees = list(dict(g.out_degree()).values())
nkk = degree_mixing_dict(g)
# generate simple directed graph with given degree sequence and joint
# degree matrix.
G = directed_joint_degree_graph(in_degrees, out_degrees, nkk)
# assert degree sequence correctness.
assert in_degrees == list(dict(G.in_degree()).values())
assert out_degrees == list(dict(G.out_degree()).values())
# assert joint degree matrix correctness.
assert nkk == degree_mixing_dict(G)

View File

@ -0,0 +1,246 @@
"""Unit tests for the :mod:`networkx.generators.lattice` module."""
from itertools import product
import pytest
import networkx as nx
from networkx.utils import edges_equal
class TestGrid2DGraph:
"""Unit tests for :func:`networkx.generators.lattice.grid_2d_graph`"""
def test_number_of_vertices(self):
m, n = 5, 6
G = nx.grid_2d_graph(m, n)
assert len(G) == m * n
def test_degree_distribution(self):
m, n = 5, 6
G = nx.grid_2d_graph(m, n)
expected_histogram = [0, 0, 4, 2 * (m + n) - 8, (m - 2) * (n - 2)]
assert nx.degree_histogram(G) == expected_histogram
def test_directed(self):
m, n = 5, 6
G = nx.grid_2d_graph(m, n)
H = nx.grid_2d_graph(m, n, create_using=nx.DiGraph())
assert H.succ == G.adj
assert H.pred == G.adj
def test_multigraph(self):
m, n = 5, 6
G = nx.grid_2d_graph(m, n)
H = nx.grid_2d_graph(m, n, create_using=nx.MultiGraph())
assert list(H.edges()) == list(G.edges())
def test_periodic(self):
G = nx.grid_2d_graph(0, 0, periodic=True)
assert dict(G.degree()) == {}
for m, n, H in [
(2, 2, nx.cycle_graph(4)),
(1, 7, nx.cycle_graph(7)),
(7, 1, nx.cycle_graph(7)),
(2, 5, nx.circular_ladder_graph(5)),
(5, 2, nx.circular_ladder_graph(5)),
(2, 4, nx.cubical_graph()),
(4, 2, nx.cubical_graph()),
]:
G = nx.grid_2d_graph(m, n, periodic=True)
assert nx.could_be_isomorphic(G, H)
def test_periodic_iterable(self):
m, n = 3, 7
for a, b in product([0, 1], [0, 1]):
G = nx.grid_2d_graph(m, n, periodic=(a, b))
assert G.number_of_nodes() == m * n
assert G.number_of_edges() == (m + a - 1) * n + (n + b - 1) * m
def test_periodic_directed(self):
G = nx.grid_2d_graph(4, 2, periodic=True)
H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.DiGraph())
assert H.succ == G.adj
assert H.pred == G.adj
def test_periodic_multigraph(self):
G = nx.grid_2d_graph(4, 2, periodic=True)
H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.MultiGraph())
assert list(G.edges()) == list(H.edges())
def test_exceptions(self):
pytest.raises(nx.NetworkXError, nx.grid_2d_graph, -3, 2)
pytest.raises(nx.NetworkXError, nx.grid_2d_graph, 3, -2)
pytest.raises(TypeError, nx.grid_2d_graph, 3.3, 2)
pytest.raises(TypeError, nx.grid_2d_graph, 3, 2.2)
def test_node_input(self):
G = nx.grid_2d_graph(4, 2, periodic=True)
H = nx.grid_2d_graph(range(4), range(2), periodic=True)
assert nx.is_isomorphic(H, G)
H = nx.grid_2d_graph("abcd", "ef", periodic=True)
assert nx.is_isomorphic(H, G)
G = nx.grid_2d_graph(5, 6)
H = nx.grid_2d_graph(range(5), range(6))
assert edges_equal(H, G)
class TestGridGraph:
"""Unit tests for :func:`networkx.generators.lattice.grid_graph`"""
def test_grid_graph(self):
"""grid_graph([n,m]) is a connected simple graph with the
following properties:
number_of_nodes = n*m
degree_histogram = [0,0,4,2*(n+m)-8,(n-2)*(m-2)]
"""
for n, m in [(3, 5), (5, 3), (4, 5), (5, 4)]:
dim = [n, m]
g = nx.grid_graph(dim)
assert len(g) == n * m
assert nx.degree_histogram(g) == [
0,
0,
4,
2 * (n + m) - 8,
(n - 2) * (m - 2),
]
for n, m in [(1, 5), (5, 1)]:
dim = [n, m]
g = nx.grid_graph(dim)
assert len(g) == n * m
assert nx.is_isomorphic(g, nx.path_graph(5))
# mg = nx.grid_graph([n,m], create_using=MultiGraph())
# assert_equal(mg.edges(), g.edges())
def test_node_input(self):
G = nx.grid_graph([range(7, 9), range(3, 6)])
assert len(G) == 2 * 3
assert nx.is_isomorphic(G, nx.grid_graph([2, 3]))
def test_periodic_iterable(self):
m, n, k = 3, 7, 5
for a, b, c in product([0, 1], [0, 1], [0, 1]):
G = nx.grid_graph([m, n, k], periodic=(a, b, c))
num_e = (m + a - 1) * n * k + (n + b - 1) * m * k + (k + c - 1) * m * n
assert G.number_of_nodes() == m * n * k
assert G.number_of_edges() == num_e
class TestHypercubeGraph:
"""Unit tests for :func:`networkx.generators.lattice.hypercube_graph`"""
def test_special_cases(self):
for n, H in [
(0, nx.null_graph()),
(1, nx.path_graph(2)),
(2, nx.cycle_graph(4)),
(3, nx.cubical_graph()),
]:
G = nx.hypercube_graph(n)
assert nx.could_be_isomorphic(G, H)
def test_degree_distribution(self):
for n in range(1, 10):
G = nx.hypercube_graph(n)
expected_histogram = [0] * n + [2**n]
assert nx.degree_histogram(G) == expected_histogram
class TestTriangularLatticeGraph:
"Tests for :func:`networkx.generators.lattice.triangular_lattice_graph`"
def test_lattice_points(self):
"""Tests that the graph is really a triangular lattice."""
for m, n in [(2, 3), (2, 2), (2, 1), (3, 3), (3, 2), (3, 4)]:
G = nx.triangular_lattice_graph(m, n)
N = (n + 1) // 2
assert len(G) == (m + 1) * (1 + N) - (n % 2) * ((m + 1) // 2)
for i, j in G.nodes():
nbrs = G[(i, j)]
if i < N:
assert (i + 1, j) in nbrs
if j < m:
assert (i, j + 1) in nbrs
if j < m and (i > 0 or j % 2) and (i < N or (j + 1) % 2):
assert (i + 1, j + 1) in nbrs or (i - 1, j + 1) in nbrs
def test_directed(self):
"""Tests for creating a directed triangular lattice."""
G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph())
H = nx.triangular_lattice_graph(3, 4, create_using=nx.DiGraph())
assert H.is_directed()
for u, v in H.edges():
assert v[1] >= u[1]
if v[1] == u[1]:
assert v[0] > u[0]
def test_multigraph(self):
"""Tests for creating a triangular lattice multigraph."""
G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph())
H = nx.triangular_lattice_graph(3, 4, create_using=nx.MultiGraph())
assert list(H.edges()) == list(G.edges())
def test_periodic(self):
G = nx.triangular_lattice_graph(4, 6, periodic=True)
assert len(G) == 12
assert G.size() == 36
# all degrees are 6
assert len([n for n, d in G.degree() if d != 6]) == 0
G = nx.triangular_lattice_graph(5, 7, periodic=True)
TLG = nx.triangular_lattice_graph
pytest.raises(nx.NetworkXError, TLG, 2, 4, periodic=True)
pytest.raises(nx.NetworkXError, TLG, 4, 4, periodic=True)
pytest.raises(nx.NetworkXError, TLG, 2, 6, periodic=True)
class TestHexagonalLatticeGraph:
"Tests for :func:`networkx.generators.lattice.hexagonal_lattice_graph`"
def test_lattice_points(self):
"""Tests that the graph is really a hexagonal lattice."""
for m, n in [(4, 5), (4, 4), (4, 3), (3, 2), (3, 3), (3, 5)]:
G = nx.hexagonal_lattice_graph(m, n)
assert len(G) == 2 * (m + 1) * (n + 1) - 2
C_6 = nx.cycle_graph(6)
hexagons = [
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)],
[(0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4)],
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)],
[(2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)],
[(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4)],
]
for hexagon in hexagons:
assert nx.is_isomorphic(G.subgraph(hexagon), C_6)
def test_directed(self):
"""Tests for creating a directed hexagonal lattice."""
G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph())
H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.DiGraph())
assert H.is_directed()
pos = nx.get_node_attributes(H, "pos")
for u, v in H.edges():
assert pos[v][1] >= pos[u][1]
if pos[v][1] == pos[u][1]:
assert pos[v][0] > pos[u][0]
def test_multigraph(self):
"""Tests for creating a hexagonal lattice multigraph."""
G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph())
H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.MultiGraph())
assert list(H.edges()) == list(G.edges())
def test_periodic(self):
G = nx.hexagonal_lattice_graph(4, 6, periodic=True)
assert len(G) == 48
assert G.size() == 72
# all degrees are 3
assert len([n for n, d in G.degree() if d != 3]) == 0
G = nx.hexagonal_lattice_graph(5, 8, periodic=True)
HLG = nx.hexagonal_lattice_graph
pytest.raises(nx.NetworkXError, HLG, 2, 7, periodic=True)
pytest.raises(nx.NetworkXError, HLG, 1, 4, periodic=True)
pytest.raises(nx.NetworkXError, HLG, 2, 1, periodic=True)

View File

@ -0,0 +1,309 @@
import pytest
import networkx as nx
from networkx.generators import line
from networkx.utils import edges_equal
class TestGeneratorLine:
def test_star(self):
G = nx.star_graph(5)
L = nx.line_graph(G)
assert nx.is_isomorphic(L, nx.complete_graph(5))
def test_path(self):
G = nx.path_graph(5)
L = nx.line_graph(G)
assert nx.is_isomorphic(L, nx.path_graph(4))
def test_cycle(self):
G = nx.cycle_graph(5)
L = nx.line_graph(G)
assert nx.is_isomorphic(L, G)
def test_digraph1(self):
G = nx.DiGraph([(0, 1), (0, 2), (0, 3)])
L = nx.line_graph(G)
# no edge graph, but with nodes
assert L.adj == {(0, 1): {}, (0, 2): {}, (0, 3): {}}
def test_multigraph1(self):
G = nx.MultiGraph([(0, 1), (0, 1), (1, 0), (0, 2), (2, 0), (0, 3)])
L = nx.line_graph(G)
# no edge graph, but with nodes
assert edges_equal(
L.edges(),
[
((0, 3, 0), (0, 1, 0)),
((0, 3, 0), (0, 2, 0)),
((0, 3, 0), (0, 2, 1)),
((0, 3, 0), (0, 1, 1)),
((0, 3, 0), (0, 1, 2)),
((0, 1, 0), (0, 1, 1)),
((0, 1, 0), (0, 2, 0)),
((0, 1, 0), (0, 1, 2)),
((0, 1, 0), (0, 2, 1)),
((0, 1, 1), (0, 1, 2)),
((0, 1, 1), (0, 2, 0)),
((0, 1, 1), (0, 2, 1)),
((0, 1, 2), (0, 2, 0)),
((0, 1, 2), (0, 2, 1)),
((0, 2, 0), (0, 2, 1)),
],
)
def test_multigraph2(self):
G = nx.MultiGraph([(1, 2), (2, 1)])
L = nx.line_graph(G)
assert edges_equal(L.edges(), [((1, 2, 0), (1, 2, 1))])
def test_multidigraph1(self):
G = nx.MultiDiGraph([(1, 2), (2, 1)])
L = nx.line_graph(G)
assert edges_equal(L.edges(), [((1, 2, 0), (2, 1, 0)), ((2, 1, 0), (1, 2, 0))])
def test_multidigraph2(self):
G = nx.MultiDiGraph([(0, 1), (0, 1), (0, 1), (1, 2)])
L = nx.line_graph(G)
assert edges_equal(
L.edges(),
[((0, 1, 0), (1, 2, 0)), ((0, 1, 1), (1, 2, 0)), ((0, 1, 2), (1, 2, 0))],
)
def test_digraph2(self):
G = nx.DiGraph([(0, 1), (1, 2), (2, 3)])
L = nx.line_graph(G)
assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
def test_create1(self):
G = nx.DiGraph([(0, 1), (1, 2), (2, 3)])
L = nx.line_graph(G, create_using=nx.Graph())
assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
def test_create2(self):
G = nx.Graph([(0, 1), (1, 2), (2, 3)])
L = nx.line_graph(G, create_using=nx.DiGraph())
assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
class TestGeneratorInverseLine:
def test_example(self):
G = nx.Graph()
G_edges = [
[1, 2],
[1, 3],
[1, 4],
[1, 5],
[2, 3],
[2, 5],
[2, 6],
[2, 7],
[3, 4],
[3, 5],
[6, 7],
[6, 8],
[7, 8],
]
G.add_edges_from(G_edges)
H = nx.inverse_line_graph(G)
solution = nx.Graph()
solution_edges = [
("a", "b"),
("a", "c"),
("a", "d"),
("a", "e"),
("c", "d"),
("e", "f"),
("e", "g"),
("f", "g"),
]
solution.add_edges_from(solution_edges)
assert nx.is_isomorphic(H, solution)
def test_example_2(self):
G = nx.Graph()
G_edges = [[1, 2], [1, 3], [2, 3], [3, 4], [3, 5], [4, 5]]
G.add_edges_from(G_edges)
H = nx.inverse_line_graph(G)
solution = nx.Graph()
solution_edges = [("a", "c"), ("b", "c"), ("c", "d"), ("d", "e"), ("d", "f")]
solution.add_edges_from(solution_edges)
assert nx.is_isomorphic(H, solution)
def test_pair(self):
G = nx.path_graph(2)
H = nx.inverse_line_graph(G)
solution = nx.path_graph(3)
assert nx.is_isomorphic(H, solution)
def test_line(self):
G = nx.path_graph(5)
solution = nx.path_graph(6)
H = nx.inverse_line_graph(G)
assert nx.is_isomorphic(H, solution)
def test_triangle_graph(self):
G = nx.complete_graph(3)
H = nx.inverse_line_graph(G)
alternative_solution = nx.Graph()
alternative_solution.add_edges_from([[0, 1], [0, 2], [0, 3]])
# there are two alternative inverse line graphs for this case
# so long as we get one of them the test should pass
assert nx.is_isomorphic(H, G) or nx.is_isomorphic(H, alternative_solution)
def test_cycle(self):
G = nx.cycle_graph(5)
H = nx.inverse_line_graph(G)
assert nx.is_isomorphic(H, G)
def test_empty(self):
G = nx.Graph()
H = nx.inverse_line_graph(G)
assert nx.is_isomorphic(H, nx.complete_graph(1))
def test_K1(self):
G = nx.complete_graph(1)
H = nx.inverse_line_graph(G)
solution = nx.path_graph(2)
assert nx.is_isomorphic(H, solution)
def test_edgeless_graph(self):
G = nx.empty_graph(5)
with pytest.raises(nx.NetworkXError, match="edgeless graph"):
nx.inverse_line_graph(G)
def test_selfloops_error(self):
G = nx.cycle_graph(4)
G.add_edge(0, 0)
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
def test_non_line_graphs(self):
# Tests several known non-line graphs for impossibility
# Adapted from L.W.Beineke, "Characterizations of derived graphs"
# claw graph
claw = nx.star_graph(3)
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, claw)
# wheel graph with 6 nodes
wheel = nx.wheel_graph(6)
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, wheel)
# K5 with one edge remove
K5m = nx.complete_graph(5)
K5m.remove_edge(0, 1)
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, K5m)
# graph without any odd triangles (contains claw as induced subgraph)
G = nx.compose(nx.path_graph(2), nx.complete_bipartite_graph(2, 3))
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
## Variations on a diamond graph
# Diamond + 2 edges (+ "roof")
G = nx.diamond_graph()
G.add_edges_from([(4, 0), (5, 3)])
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
G.add_edge(4, 5)
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
# Diamond + 2 connected edges
G = nx.diamond_graph()
G.add_edges_from([(4, 0), (4, 3)])
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
# Diamond + K3 + one edge (+ 2*K3)
G = nx.diamond_graph()
G.add_edges_from([(4, 0), (4, 1), (4, 2), (5, 3)])
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
G.add_edges_from([(5, 1), (5, 2)])
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
# 4 triangles
G = nx.diamond_graph()
G.add_edges_from([(4, 0), (4, 1), (5, 2), (5, 3)])
pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
def test_wrong_graph_type(self):
G = nx.DiGraph()
G_edges = [[0, 1], [0, 2], [0, 3]]
G.add_edges_from(G_edges)
pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G)
G = nx.MultiGraph()
G_edges = [[0, 1], [0, 2], [0, 3]]
G.add_edges_from(G_edges)
pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G)
def test_line_inverse_line_complete(self):
G = nx.complete_graph(10)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_path(self):
G = nx.path_graph(10)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_hypercube(self):
G = nx.hypercube_graph(5)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_cycle(self):
G = nx.cycle_graph(10)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_star(self):
G = nx.star_graph(20)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_multipartite(self):
G = nx.complete_multipartite_graph(3, 4, 5)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_inverse_line_dgm(self):
G = nx.dorogovtsev_goltsev_mendes_graph(4)
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
def test_line_different_node_types(self):
G = nx.path_graph([1, 2, 3, "a", "b", "c"])
H = nx.line_graph(G)
J = nx.inverse_line_graph(H)
assert nx.is_isomorphic(G, J)
class TestGeneratorPrivateFunctions:
def test_triangles_error(self):
G = nx.diamond_graph()
pytest.raises(nx.NetworkXError, line._triangles, G, (4, 0))
pytest.raises(nx.NetworkXError, line._triangles, G, (0, 3))
def test_odd_triangles_error(self):
G = nx.diamond_graph()
pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 4))
pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 3))
def test_select_starting_cell_error(self):
G = nx.diamond_graph()
pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (4, 0))
pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (0, 3))
def test_diamond_graph(self):
G = nx.diamond_graph()
for edge in G.edges:
cell = line._select_starting_cell(G, starting_edge=edge)
# Starting cell should always be one of the two triangles
assert len(cell) == 3
assert all(v in G[u] for u in cell for v in cell if u != v)

View File

@ -0,0 +1,30 @@
"""Unit tests for the :mod:`networkx.generators.mycielski` module."""
import pytest
import networkx as nx
class TestMycielski:
def test_construction(self):
G = nx.path_graph(2)
M = nx.mycielskian(G)
assert nx.is_isomorphic(M, nx.cycle_graph(5))
def test_size(self):
G = nx.path_graph(2)
M = nx.mycielskian(G, 2)
assert len(M) == 11
assert M.size() == 20
def test_mycielski_graph_generator(self):
G = nx.mycielski_graph(1)
assert nx.is_isomorphic(G, nx.empty_graph(1))
G = nx.mycielski_graph(2)
assert nx.is_isomorphic(G, nx.path_graph(2))
G = nx.mycielski_graph(3)
assert nx.is_isomorphic(G, nx.cycle_graph(5))
G = nx.mycielski_graph(4)
assert nx.is_isomorphic(G, nx.mycielskian(nx.cycle_graph(5)))
with pytest.raises(nx.NetworkXError, match="must satisfy n >= 1"):
nx.mycielski_graph(0)

View File

@ -0,0 +1,68 @@
"""
Unit tests for WROM algorithm generator in generators/nonisomorphic_trees.py
"""
import pytest
import networkx as nx
from networkx.utils import edges_equal
class TestGeneratorNonIsomorphicTrees:
def test_tree_structure(self):
# test for tree structure for nx.nonisomorphic_trees()
def f(x):
return list(nx.nonisomorphic_trees(x))
for i in f(6):
assert nx.is_tree(i)
for i in f(8):
assert nx.is_tree(i)
def test_nonisomorphism(self):
# test for nonisomorphism of trees for nx.nonisomorphic_trees()
def f(x):
return list(nx.nonisomorphic_trees(x))
trees = f(6)
for i in range(len(trees)):
for j in range(i + 1, len(trees)):
assert not nx.is_isomorphic(trees[i], trees[j])
trees = f(8)
for i in range(len(trees)):
for j in range(i + 1, len(trees)):
assert not nx.is_isomorphic(trees[i], trees[j])
def test_number_of_nonisomorphic_trees(self):
# http://oeis.org/A000055
assert nx.number_of_nonisomorphic_trees(2) == 1
assert nx.number_of_nonisomorphic_trees(3) == 1
assert nx.number_of_nonisomorphic_trees(4) == 2
assert nx.number_of_nonisomorphic_trees(5) == 3
assert nx.number_of_nonisomorphic_trees(6) == 6
assert nx.number_of_nonisomorphic_trees(7) == 11
assert nx.number_of_nonisomorphic_trees(8) == 23
def test_nonisomorphic_trees(self):
def f(x):
return list(nx.nonisomorphic_trees(x))
assert edges_equal(f(3)[0].edges(), [(0, 1), (0, 2)])
assert edges_equal(f(4)[0].edges(), [(0, 1), (0, 3), (1, 2)])
assert edges_equal(f(4)[1].edges(), [(0, 1), (0, 2), (0, 3)])
def test_nonisomorphic_trees_matrix(self):
trees_2 = [[[0, 1], [1, 0]]]
with pytest.deprecated_call():
assert list(nx.nonisomorphic_trees(2, create="matrix")) == trees_2
trees_3 = [[[0, 1, 1], [1, 0, 0], [1, 0, 0]]]
with pytest.deprecated_call():
assert list(nx.nonisomorphic_trees(3, create="matrix")) == trees_3
trees_4 = [
[[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]],
[[0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]],
]
with pytest.deprecated_call():
assert list(nx.nonisomorphic_trees(4, create="matrix")) == trees_4

View File

@ -0,0 +1,33 @@
import pytest
import networkx as nx
class TestRandomClusteredGraph:
def test_custom_joint_degree_sequence(self):
node = [1, 1, 1, 2, 1, 2, 0, 0]
tri = [0, 0, 0, 0, 0, 1, 1, 1]
joint_degree_sequence = zip(node, tri)
G = nx.random_clustered_graph(joint_degree_sequence)
assert G.number_of_nodes() == 8
assert G.number_of_edges() == 7
def test_tuple_joint_degree_sequence(self):
G = nx.random_clustered_graph([(1, 2), (2, 1), (1, 1), (1, 1), (1, 1), (2, 0)])
assert G.number_of_nodes() == 6
assert G.number_of_edges() == 10
def test_invalid_joint_degree_sequence_type(self):
with pytest.raises(nx.NetworkXError, match="Invalid degree sequence"):
nx.random_clustered_graph([[1, 1], [2, 1], [0, 1]])
def test_invalid_joint_degree_sequence_value(self):
with pytest.raises(nx.NetworkXError, match="Invalid degree sequence"):
nx.random_clustered_graph([[1, 1], [1, 2], [0, 1]])
def test_directed_graph_raises_error(self):
with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"):
nx.random_clustered_graph(
[(1, 2), (2, 1), (1, 1), (1, 1), (1, 1), (2, 0)],
create_using=nx.DiGraph,
)

View File

@ -0,0 +1,478 @@
"""Unit tests for the :mod:`networkx.generators.random_graphs` module."""
import pytest
import networkx as nx
_gnp_generators = [
nx.gnp_random_graph,
nx.fast_gnp_random_graph,
nx.binomial_graph,
nx.erdos_renyi_graph,
]
@pytest.mark.parametrize("generator", _gnp_generators)
@pytest.mark.parametrize("directed", (True, False))
def test_gnp_generators_negative_edge_probability(generator, directed):
"""If the edge probability `p` is <=0, the resulting graph should have no edges."""
G = generator(10, -1.1, directed=directed)
assert len(G) == 10
assert G.number_of_edges() == 0
assert G.is_directed() == directed
@pytest.mark.parametrize("generator", _gnp_generators)
@pytest.mark.parametrize(
("directed", "expected_num_edges"),
[(False, 45), (True, 90)],
)
def test_gnp_generators_greater_than_1_edge_probability(
generator, directed, expected_num_edges
):
"""If the edge probability `p` is >=1, the resulting graph should be complete."""
G = generator(10, 1.1, directed=directed)
assert len(G) == 10
assert G.number_of_edges() == expected_num_edges
assert G.is_directed() == directed
@pytest.mark.parametrize("generator", _gnp_generators)
@pytest.mark.parametrize("directed", (True, False))
def test_gnp_generators_basic(generator, directed):
"""If the edge probability `p` is >0 and <1, test only the basic properties."""
G = generator(10, 0.1, directed=directed)
assert len(G) == 10
assert G.is_directed() == directed
@pytest.mark.parametrize("generator", _gnp_generators)
def test_gnp_generators_for_p_close_to_1(generator):
"""If the edge probability `p` is close to 1, the resulting graph should have all edges."""
runs = 100
edges = sum(
generator(10, 0.99999, directed=True).number_of_edges() for _ in range(runs)
)
assert abs(edges / float(runs) - 90) <= runs * 2.0 / 100
@pytest.mark.parametrize("generator", _gnp_generators)
@pytest.mark.parametrize("p", (0.2, 0.8))
@pytest.mark.parametrize("directed", (True, False))
def test_gnp_generators_edge_probability(generator, p, directed):
"""Test that gnp generators generate edges according to the their probability `p`."""
runs = 5000
n = 5
edge_counts = [[0] * n for _ in range(n)]
for i in range(runs):
G = generator(n, p, directed=directed)
for v, w in G.edges:
edge_counts[v][w] += 1
if not directed:
edge_counts[w][v] += 1
for v in range(n):
for w in range(n):
if v == w:
# There should be no loops
assert edge_counts[v][w] == 0
else:
# Each edge should have been generated with probability close to p
assert abs(edge_counts[v][w] / float(runs) - p) <= 0.03
@pytest.mark.parametrize(
"generator", [nx.gnp_random_graph, nx.binomial_graph, nx.erdos_renyi_graph]
)
@pytest.mark.parametrize(
("seed", "directed", "expected_num_edges"),
[(42, False, 1219), (42, True, 2454), (314, False, 1247), (314, True, 2476)],
)
def test_gnp_random_graph_aliases(generator, seed, directed, expected_num_edges):
"""Test that aliases give the same result with the same seed."""
G = generator(100, 0.25, seed=seed, directed=directed)
assert len(G) == 100
assert G.number_of_edges() == expected_num_edges
assert G.is_directed() == directed
class TestGeneratorsRandom:
def test_random_graph(self):
seed = 42
G = nx.gnm_random_graph(100, 20, seed)
G = nx.gnm_random_graph(100, 20, seed, directed=True)
G = nx.dense_gnm_random_graph(100, 20, seed)
G = nx.barabasi_albert_graph(100, 1, seed)
G = nx.barabasi_albert_graph(100, 3, seed)
assert G.number_of_edges() == (97 * 3)
G = nx.barabasi_albert_graph(100, 3, seed, nx.complete_graph(5))
assert G.number_of_edges() == (10 + 95 * 3)
G = nx.extended_barabasi_albert_graph(100, 1, 0, 0, seed)
assert G.number_of_edges() == 99
G = nx.extended_barabasi_albert_graph(100, 3, 0, 0, seed)
assert G.number_of_edges() == 97 * 3
G = nx.extended_barabasi_albert_graph(100, 1, 0, 0.5, seed)
assert G.number_of_edges() == 99
G = nx.extended_barabasi_albert_graph(100, 2, 0.5, 0, seed)
assert G.number_of_edges() > 100 * 3
assert G.number_of_edges() < 100 * 4
G = nx.extended_barabasi_albert_graph(100, 2, 0.3, 0.3, seed)
assert G.number_of_edges() > 100 * 2
assert G.number_of_edges() < 100 * 4
G = nx.powerlaw_cluster_graph(100, 1, 1.0, seed)
G = nx.powerlaw_cluster_graph(100, 3, 0.0, seed)
assert G.number_of_edges() == (97 * 3)
G = nx.random_regular_graph(10, 20, seed)
pytest.raises(nx.NetworkXError, nx.random_regular_graph, 3, 21)
pytest.raises(nx.NetworkXError, nx.random_regular_graph, 33, 21)
constructor = [(10, 20, 0.8), (20, 40, 0.8)]
G = nx.random_shell_graph(constructor, seed)
def is_caterpillar(g):
"""
A tree is a caterpillar iff all nodes of degree >=3 are surrounded
by at most two nodes of degree two or greater.
ref: http://mathworld.wolfram.com/CaterpillarGraph.html
"""
deg_over_3 = [n for n in g if g.degree(n) >= 3]
for n in deg_over_3:
nbh_deg_over_2 = [nbh for nbh in g.neighbors(n) if g.degree(nbh) >= 2]
if not len(nbh_deg_over_2) <= 2:
return False
return True
def is_lobster(g):
"""
A tree is a lobster if it has the property that the removal of leaf
nodes leaves a caterpillar graph (Gallian 2007)
ref: http://mathworld.wolfram.com/LobsterGraph.html
"""
non_leafs = [n for n in g if g.degree(n) > 1]
return is_caterpillar(g.subgraph(non_leafs))
G = nx.random_lobster(10, 0.1, 0.5, seed)
assert max(G.degree(n) for n in G.nodes()) > 3
assert is_lobster(G)
pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 0.1, 1, seed)
pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 1, 1, seed)
pytest.raises(nx.NetworkXError, nx.random_lobster, 10, 1, 0.5, seed)
# docstring says this should be a caterpillar
G = nx.random_lobster(10, 0.1, 0.0, seed)
assert is_caterpillar(G)
# difficult to find seed that requires few tries
seq = nx.random_powerlaw_tree_sequence(10, 3, seed=14, tries=1)
G = nx.random_powerlaw_tree(10, 3, seed=14, tries=1)
def test_dual_barabasi_albert(self, m1=1, m2=4, p=0.5):
"""
Tests that the dual BA random graph generated behaves consistently.
Tests the exceptions are raised as expected.
The graphs generation are repeated several times to prevent lucky shots
"""
seeds = [42, 314, 2718]
initial_graph = nx.complete_graph(10)
for seed in seeds:
# This should be BA with m = m1
BA1 = nx.barabasi_albert_graph(100, m1, seed)
DBA1 = nx.dual_barabasi_albert_graph(100, m1, m2, 1, seed)
assert BA1.edges() == DBA1.edges()
# This should be BA with m = m2
BA2 = nx.barabasi_albert_graph(100, m2, seed)
DBA2 = nx.dual_barabasi_albert_graph(100, m1, m2, 0, seed)
assert BA2.edges() == DBA2.edges()
BA3 = nx.barabasi_albert_graph(100, m1, seed)
DBA3 = nx.dual_barabasi_albert_graph(100, m1, m1, p, seed)
# We can't compare edges here since randomness is "consumed" when drawing
# between m1 and m2
assert BA3.size() == DBA3.size()
DBA = nx.dual_barabasi_albert_graph(100, m1, m2, p, seed, initial_graph)
BA1 = nx.barabasi_albert_graph(100, m1, seed, initial_graph)
BA2 = nx.barabasi_albert_graph(100, m2, seed, initial_graph)
assert (
min(BA1.size(), BA2.size()) <= DBA.size() <= max(BA1.size(), BA2.size())
)
# Testing exceptions
dbag = nx.dual_barabasi_albert_graph
pytest.raises(nx.NetworkXError, dbag, m1, m1, m2, 0)
pytest.raises(nx.NetworkXError, dbag, m2, m1, m2, 0)
pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, -0.5)
pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, 1.5)
initial = nx.complete_graph(max(m1, m2) - 1)
pytest.raises(nx.NetworkXError, dbag, 100, m1, m2, p, initial_graph=initial)
def test_extended_barabasi_albert(self, m=2):
"""
Tests that the extended BA random graph generated behaves consistently.
Tests the exceptions are raised as expected.
The graphs generation are repeated several times to prevent lucky-shots
"""
seeds = [42, 314, 2718]
for seed in seeds:
BA_model = nx.barabasi_albert_graph(100, m, seed)
BA_model_edges = BA_model.number_of_edges()
# This behaves just like BA, the number of edges must be the same
G1 = nx.extended_barabasi_albert_graph(100, m, 0, 0, seed)
assert G1.size() == BA_model_edges
# More than twice more edges should have been added
G1 = nx.extended_barabasi_albert_graph(100, m, 0.8, 0, seed)
assert G1.size() > BA_model_edges * 2
# Only edge rewiring, so the number of edges less than original
G2 = nx.extended_barabasi_albert_graph(100, m, 0, 0.8, seed)
assert G2.size() == BA_model_edges
# Mixed scenario: less edges than G1 and more edges than G2
G3 = nx.extended_barabasi_albert_graph(100, m, 0.3, 0.3, seed)
assert G3.size() > G2.size()
assert G3.size() < G1.size()
# Testing exceptions
ebag = nx.extended_barabasi_albert_graph
pytest.raises(nx.NetworkXError, ebag, m, m, 0, 0)
pytest.raises(nx.NetworkXError, ebag, 1, 0.5, 0, 0)
pytest.raises(nx.NetworkXError, ebag, 100, 2, 0.5, 0.5)
def test_random_zero_regular_graph(self):
"""Tests that a 0-regular graph has the correct number of nodes and
edges.
"""
seed = 42
G = nx.random_regular_graph(0, 10, seed)
assert len(G) == 10
assert G.number_of_edges() == 0
def test_gnm(self):
G = nx.gnm_random_graph(10, 3)
assert len(G) == 10
assert G.number_of_edges() == 3
G = nx.gnm_random_graph(10, 3, seed=42)
assert len(G) == 10
assert G.number_of_edges() == 3
G = nx.gnm_random_graph(10, 100)
assert len(G) == 10
assert G.number_of_edges() == 45
G = nx.gnm_random_graph(10, 100, directed=True)
assert len(G) == 10
assert G.number_of_edges() == 90
G = nx.gnm_random_graph(10, -1.1)
assert len(G) == 10
assert G.number_of_edges() == 0
def test_watts_strogatz_big_k(self):
# Test to make sure than n <= k
pytest.raises(nx.NetworkXError, nx.watts_strogatz_graph, 10, 11, 0.25)
pytest.raises(nx.NetworkXError, nx.newman_watts_strogatz_graph, 10, 11, 0.25)
# could create an infinite loop, now doesn't
# infinite loop used to occur when a node has degree n-1 and needs to rewire
nx.watts_strogatz_graph(10, 9, 0.25, seed=0)
nx.newman_watts_strogatz_graph(10, 9, 0.5, seed=0)
# Test k==n scenario
nx.watts_strogatz_graph(10, 10, 0.25, seed=0)
nx.newman_watts_strogatz_graph(10, 10, 0.25, seed=0)
def test_random_kernel_graph(self):
def integral(u, w, z):
return c * (z - w)
def root(u, w, r):
return r / c + w
c = 1
graph = nx.random_kernel_graph(1000, integral, root)
graph = nx.random_kernel_graph(1000, integral, root, seed=42)
assert len(graph) == 1000
@pytest.mark.parametrize(
("k", "expected_num_nodes", "expected_num_edges"),
[
(2, 10, 10),
(4, 10, 20),
],
)
def test_watts_strogatz(k, expected_num_nodes, expected_num_edges):
G = nx.watts_strogatz_graph(10, k, 0.25, seed=42)
assert len(G) == expected_num_nodes
assert G.number_of_edges() == expected_num_edges
def test_newman_watts_strogatz_zero_probability():
G = nx.newman_watts_strogatz_graph(10, 2, 0.0, seed=42)
assert len(G) == 10
assert G.number_of_edges() == 10
def test_newman_watts_strogatz_nonzero_probability():
G = nx.newman_watts_strogatz_graph(10, 4, 0.25, seed=42)
assert len(G) == 10
assert G.number_of_edges() >= 20
def test_connected_watts_strogatz():
G = nx.connected_watts_strogatz_graph(10, 2, 0.1, tries=10, seed=42)
assert len(G) == 10
assert G.number_of_edges() == 10
def test_connected_watts_strogatz_zero_tries():
with pytest.raises(nx.NetworkXError, match="Maximum number of tries exceeded"):
nx.connected_watts_strogatz_graph(10, 2, 0.1, tries=0)
@pytest.mark.parametrize(
"generator, kwargs",
[
(nx.fast_gnp_random_graph, {"n": 20, "p": 0.2, "directed": False}),
(nx.fast_gnp_random_graph, {"n": 20, "p": 0.2, "directed": True}),
(nx.gnp_random_graph, {"n": 20, "p": 0.2, "directed": False}),
(nx.gnp_random_graph, {"n": 20, "p": 0.2, "directed": True}),
(nx.dense_gnm_random_graph, {"n": 30, "m": 4}),
(nx.gnm_random_graph, {"n": 30, "m": 4, "directed": False}),
(nx.gnm_random_graph, {"n": 30, "m": 4, "directed": True}),
(nx.newman_watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}),
(nx.watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}),
(nx.connected_watts_strogatz_graph, {"n": 50, "k": 5, "p": 0.1}),
(nx.random_regular_graph, {"d": 5, "n": 20}),
(nx.barabasi_albert_graph, {"n": 40, "m": 3}),
(nx.dual_barabasi_albert_graph, {"n": 40, "m1": 3, "m2": 2, "p": 0.1}),
(nx.extended_barabasi_albert_graph, {"n": 40, "m": 3, "p": 0.1, "q": 0.2}),
(nx.powerlaw_cluster_graph, {"n": 40, "m": 3, "p": 0.1}),
(nx.random_lobster, {"n": 40, "p1": 0.1, "p2": 0.2}),
(nx.random_shell_graph, {"constructor": [(10, 20, 0.8), (20, 40, 0.8)]}),
(nx.random_powerlaw_tree, {"n": 10, "seed": 14, "tries": 1}),
(
nx.random_kernel_graph,
{
"n": 10,
"kernel_integral": lambda u, w, z: z - w,
"kernel_root": lambda u, w, r: r + w,
},
),
],
)
@pytest.mark.parametrize("create_using_instance", [False, True])
def test_create_using(generator, kwargs, create_using_instance):
class DummyGraph(nx.Graph):
pass
class DummyDiGraph(nx.DiGraph):
pass
create_using_type = DummyDiGraph if kwargs.get("directed") else DummyGraph
create_using = create_using_type() if create_using_instance else create_using_type
graph = generator(**kwargs, create_using=create_using)
assert isinstance(graph, create_using_type)
@pytest.mark.parametrize("directed", [True, False])
@pytest.mark.parametrize("fn", (nx.fast_gnp_random_graph, nx.gnp_random_graph))
def test_gnp_fns_disallow_multigraph(fn, directed):
with pytest.raises(nx.NetworkXError, match="must not be a multi-graph"):
fn(20, 0.2, create_using=nx.MultiGraph)
@pytest.mark.parametrize("fn", (nx.gnm_random_graph, nx.dense_gnm_random_graph))
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_gnm_fns_disallow_directed_and_multigraph(fn, graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
fn(10, 20, create_using=graphtype)
@pytest.mark.parametrize(
"fn",
(
nx.newman_watts_strogatz_graph,
nx.watts_strogatz_graph,
nx.connected_watts_strogatz_graph,
),
)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_watts_strogatz_disallow_directed_and_multigraph(fn, graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
fn(10, 2, 0.2, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_random_regular_graph_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.random_regular_graph(2, 10, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_barabasi_albert_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.barabasi_albert_graph(10, 3, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_dual_barabasi_albert_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.dual_barabasi_albert_graph(10, 2, 1, 0.4, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_extended_barabasi_albert_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.extended_barabasi_albert_graph(10, 2, 0.2, 0.3, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_powerlaw_cluster_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.powerlaw_cluster_graph(10, 5, 0.2, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_random_lobster_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.random_lobster(10, 0.1, 0.1, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_random_shell_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.random_shell_graph([(10, 20, 2), (10, 20, 5)], create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_random_powerlaw_tree_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.random_powerlaw_tree(10, create_using=graphtype)
@pytest.mark.parametrize("graphtype", (nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph))
def test_random_kernel_disallow_directed_and_multigraph(graphtype):
with pytest.raises(nx.NetworkXError, match="must not be"):
nx.random_kernel_graph(
10, lambda y, a, b: a + b, lambda u, w, r: r + w, create_using=graphtype
)

View File

@ -0,0 +1,208 @@
import pytest
import networkx as nx
from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic
is_isomorphic = graph_could_be_isomorphic
"""Generators - Small
=====================
Some small graphs
"""
null = nx.null_graph()
class TestGeneratorsSmall:
def test__LCF_graph(self):
# If n<=0, then return the null_graph
G = nx.LCF_graph(-10, [1, 2], 100)
assert is_isomorphic(G, null)
G = nx.LCF_graph(0, [1, 2], 3)
assert is_isomorphic(G, null)
G = nx.LCF_graph(0, [1, 2], 10)
assert is_isomorphic(G, null)
# Test that LCF(n,[],0) == cycle_graph(n)
for a, b, c in [(5, [], 0), (10, [], 0), (5, [], 1), (10, [], 10)]:
G = nx.LCF_graph(a, b, c)
assert is_isomorphic(G, nx.cycle_graph(a))
# Generate the utility graph K_{3,3}
G = nx.LCF_graph(6, [3, -3], 3)
utility_graph = nx.complete_bipartite_graph(3, 3)
assert is_isomorphic(G, utility_graph)
with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"):
G = nx.LCF_graph(6, [3, -3], 3, create_using=nx.DiGraph)
def test_properties_named_small_graphs(self):
G = nx.bull_graph()
assert sorted(G) == list(range(5))
assert G.number_of_edges() == 5
assert sorted(d for n, d in G.degree()) == [1, 1, 2, 3, 3]
assert nx.diameter(G) == 3
assert nx.radius(G) == 2
G = nx.chvatal_graph()
assert sorted(G) == list(range(12))
assert G.number_of_edges() == 24
assert [d for n, d in G.degree()] == 12 * [4]
assert nx.diameter(G) == 2
assert nx.radius(G) == 2
G = nx.cubical_graph()
assert sorted(G) == list(range(8))
assert G.number_of_edges() == 12
assert [d for n, d in G.degree()] == 8 * [3]
assert nx.diameter(G) == 3
assert nx.radius(G) == 3
G = nx.desargues_graph()
assert sorted(G) == list(range(20))
assert G.number_of_edges() == 30
assert [d for n, d in G.degree()] == 20 * [3]
G = nx.diamond_graph()
assert sorted(G) == list(range(4))
assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3]
assert nx.diameter(G) == 2
assert nx.radius(G) == 1
G = nx.dodecahedral_graph()
assert sorted(G) == list(range(20))
assert G.number_of_edges() == 30
assert [d for n, d in G.degree()] == 20 * [3]
assert nx.diameter(G) == 5
assert nx.radius(G) == 5
G = nx.frucht_graph()
assert sorted(G) == list(range(12))
assert G.number_of_edges() == 18
assert [d for n, d in G.degree()] == 12 * [3]
assert nx.diameter(G) == 4
assert nx.radius(G) == 3
G = nx.heawood_graph()
assert sorted(G) == list(range(14))
assert G.number_of_edges() == 21
assert [d for n, d in G.degree()] == 14 * [3]
assert nx.diameter(G) == 3
assert nx.radius(G) == 3
G = nx.hoffman_singleton_graph()
assert sorted(G) == list(range(50))
assert G.number_of_edges() == 175
assert [d for n, d in G.degree()] == 50 * [7]
assert nx.diameter(G) == 2
assert nx.radius(G) == 2
G = nx.house_graph()
assert sorted(G) == list(range(5))
assert G.number_of_edges() == 6
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 3, 3]
assert nx.diameter(G) == 2
assert nx.radius(G) == 2
G = nx.house_x_graph()
assert sorted(G) == list(range(5))
assert G.number_of_edges() == 8
assert sorted(d for n, d in G.degree()) == [2, 3, 3, 4, 4]
assert nx.diameter(G) == 2
assert nx.radius(G) == 1
G = nx.icosahedral_graph()
assert sorted(G) == list(range(12))
assert G.number_of_edges() == 30
assert [d for n, d in G.degree()] == [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
assert nx.diameter(G) == 3
assert nx.radius(G) == 3
G = nx.krackhardt_kite_graph()
assert sorted(G) == list(range(10))
assert G.number_of_edges() == 18
assert sorted(d for n, d in G.degree()) == [1, 2, 3, 3, 3, 4, 4, 5, 5, 6]
G = nx.moebius_kantor_graph()
assert sorted(G) == list(range(16))
assert G.number_of_edges() == 24
assert [d for n, d in G.degree()] == 16 * [3]
assert nx.diameter(G) == 4
G = nx.octahedral_graph()
assert sorted(G) == list(range(6))
assert G.number_of_edges() == 12
assert [d for n, d in G.degree()] == 6 * [4]
assert nx.diameter(G) == 2
assert nx.radius(G) == 2
G = nx.pappus_graph()
assert sorted(G) == list(range(18))
assert G.number_of_edges() == 27
assert [d for n, d in G.degree()] == 18 * [3]
assert nx.diameter(G) == 4
G = nx.petersen_graph()
assert sorted(G) == list(range(10))
assert G.number_of_edges() == 15
assert [d for n, d in G.degree()] == 10 * [3]
assert nx.diameter(G) == 2
assert nx.radius(G) == 2
G = nx.sedgewick_maze_graph()
assert sorted(G) == list(range(8))
assert G.number_of_edges() == 10
assert sorted(d for n, d in G.degree()) == [1, 2, 2, 2, 3, 3, 3, 4]
G = nx.tetrahedral_graph()
assert sorted(G) == list(range(4))
assert G.number_of_edges() == 6
assert [d for n, d in G.degree()] == [3, 3, 3, 3]
assert nx.diameter(G) == 1
assert nx.radius(G) == 1
G = nx.truncated_cube_graph()
assert sorted(G) == list(range(24))
assert G.number_of_edges() == 36
assert [d for n, d in G.degree()] == 24 * [3]
G = nx.truncated_tetrahedron_graph()
assert sorted(G) == list(range(12))
assert G.number_of_edges() == 18
assert [d for n, d in G.degree()] == 12 * [3]
G = nx.tutte_graph()
assert sorted(G) == list(range(46))
assert G.number_of_edges() == 69
assert [d for n, d in G.degree()] == 46 * [3]
# Test create_using with directed or multigraphs on small graphs
pytest.raises(nx.NetworkXError, nx.tutte_graph, create_using=nx.DiGraph)
MG = nx.tutte_graph(create_using=nx.MultiGraph)
assert sorted(MG.edges()) == sorted(G.edges())
@pytest.mark.parametrize(
"fn",
(
nx.bull_graph,
nx.chvatal_graph,
nx.cubical_graph,
nx.diamond_graph,
nx.house_graph,
nx.house_x_graph,
nx.icosahedral_graph,
nx.krackhardt_kite_graph,
nx.octahedral_graph,
nx.petersen_graph,
nx.truncated_cube_graph,
nx.tutte_graph,
),
)
@pytest.mark.parametrize(
"create_using", (nx.DiGraph, nx.MultiDiGraph, nx.DiGraph([(0, 1)]))
)
def tests_raises_with_directed_create_using(fn, create_using):
with pytest.raises(nx.NetworkXError, match="Directed Graph not supported"):
fn(create_using=create_using)

View File

@ -0,0 +1,49 @@
import pytest
pytest.importorskip("numpy")
pytest.importorskip("scipy")
from networkx import is_isomorphic
from networkx.exception import NetworkXError
from networkx.generators import karate_club_graph
from networkx.generators.spectral_graph_forge import spectral_graph_forge
from networkx.utils import nodes_equal
def test_spectral_graph_forge():
G = karate_club_graph()
seed = 54321
# common cases, just checking node number preserving and difference
# between identity and modularity cases
H = spectral_graph_forge(G, 0.1, transformation="identity", seed=seed)
assert nodes_equal(G, H)
I = spectral_graph_forge(G, 0.1, transformation="identity", seed=seed)
assert nodes_equal(G, H)
assert is_isomorphic(I, H)
I = spectral_graph_forge(G, 0.1, transformation="modularity", seed=seed)
assert nodes_equal(G, I)
assert not is_isomorphic(I, H)
# with all the eigenvectors, output graph is identical to the input one
H = spectral_graph_forge(G, 1, transformation="modularity", seed=seed)
assert nodes_equal(G, H)
assert is_isomorphic(G, H)
# invalid alpha input value, it is silently truncated in [0,1]
H = spectral_graph_forge(G, -1, transformation="identity", seed=seed)
assert nodes_equal(G, H)
H = spectral_graph_forge(G, 10, transformation="identity", seed=seed)
assert nodes_equal(G, H)
assert is_isomorphic(G, H)
# invalid transformation mode, checking the error raising
pytest.raises(
NetworkXError, spectral_graph_forge, G, 0.1, transformation="unknown", seed=seed
)

View File

@ -0,0 +1,72 @@
"""Unit tests for the :mod:`networkx.generators.stochastic` module."""
import pytest
import networkx as nx
class TestStochasticGraph:
"""Unit tests for the :func:`~networkx.stochastic_graph` function."""
def test_default_weights(self):
G = nx.DiGraph()
G.add_edge(0, 1)
G.add_edge(0, 2)
S = nx.stochastic_graph(G)
assert nx.is_isomorphic(G, S)
assert sorted(S.edges(data=True)) == [
(0, 1, {"weight": 0.5}),
(0, 2, {"weight": 0.5}),
]
def test_in_place(self):
"""Tests for an in-place reweighting of the edges of the graph."""
G = nx.DiGraph()
G.add_edge(0, 1, weight=1)
G.add_edge(0, 2, weight=1)
nx.stochastic_graph(G, copy=False)
assert sorted(G.edges(data=True)) == [
(0, 1, {"weight": 0.5}),
(0, 2, {"weight": 0.5}),
]
def test_arbitrary_weights(self):
G = nx.DiGraph()
G.add_edge(0, 1, weight=1)
G.add_edge(0, 2, weight=1)
S = nx.stochastic_graph(G)
assert sorted(S.edges(data=True)) == [
(0, 1, {"weight": 0.5}),
(0, 2, {"weight": 0.5}),
]
def test_multidigraph(self):
G = nx.MultiDiGraph()
G.add_edges_from([(0, 1), (0, 1), (0, 2), (0, 2)])
S = nx.stochastic_graph(G)
d = {"weight": 0.25}
assert sorted(S.edges(data=True)) == [
(0, 1, d),
(0, 1, d),
(0, 2, d),
(0, 2, d),
]
def test_zero_weights(self):
"""Smoke test: ensure ZeroDivisionError is not raised."""
G = nx.DiGraph()
G.add_edge(0, 1, weight=0)
G.add_edge(0, 2, weight=0)
S = nx.stochastic_graph(G)
assert sorted(S.edges(data=True)) == [
(0, 1, {"weight": 0}),
(0, 2, {"weight": 0}),
]
def test_graph_disallowed(self):
with pytest.raises(nx.NetworkXNotImplemented):
nx.stochastic_graph(nx.Graph())
def test_multigraph_disallowed(self):
with pytest.raises(nx.NetworkXNotImplemented):
nx.stochastic_graph(nx.MultiGraph())

View File

@ -0,0 +1,92 @@
"""Unit tests for the :mod:`networkx.generators.sudoku_graph` module."""
import pytest
import networkx as nx
def test_sudoku_negative():
"""Raise an error when generating a Sudoku graph of order -1."""
pytest.raises(nx.NetworkXError, nx.sudoku_graph, n=-1)
@pytest.mark.parametrize("n", [0, 1, 2, 3, 4])
def test_sudoku_generator(n):
"""Generate Sudoku graphs of various sizes and verify their properties."""
G = nx.sudoku_graph(n)
expected_nodes = n**4
expected_degree = (n - 1) * (3 * n + 1)
expected_edges = expected_nodes * expected_degree // 2
assert not G.is_directed()
assert not G.is_multigraph()
assert G.number_of_nodes() == expected_nodes
assert G.number_of_edges() == expected_edges
assert all(d == expected_degree for _, d in G.degree)
if n == 2:
assert sorted(G.neighbors(6)) == [2, 3, 4, 5, 7, 10, 14]
elif n == 3:
assert sorted(G.neighbors(42)) == [
6,
15,
24,
33,
34,
35,
36,
37,
38,
39,
40,
41,
43,
44,
51,
52,
53,
60,
69,
78,
]
elif n == 4:
assert sorted(G.neighbors(0)) == [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
32,
33,
34,
35,
48,
49,
50,
51,
64,
80,
96,
112,
128,
144,
160,
176,
192,
208,
224,
240,
]

View File

@ -0,0 +1,64 @@
"""Unit tests for the :mod:`networkx.generators.time_series` module."""
import itertools
import networkx as nx
def test_visibility_graph__empty_series__empty_graph():
null_graph = nx.visibility_graph([]) # move along nothing to see here
assert nx.is_empty(null_graph)
def test_visibility_graph__single_value_ts__single_node_graph():
node_graph = nx.visibility_graph([10]) # So Lonely
assert node_graph.number_of_nodes() == 1
assert node_graph.number_of_edges() == 0
def test_visibility_graph__two_values_ts__single_edge_graph():
edge_graph = nx.visibility_graph([10, 20]) # Two of Us
assert list(edge_graph.edges) == [(0, 1)]
def test_visibility_graph__convex_series__complete_graph():
series = [i**2 for i in range(10)] # no obstructions
expected_series_length = len(series)
actual_graph = nx.visibility_graph(series)
assert actual_graph.number_of_nodes() == expected_series_length
assert actual_graph.number_of_edges() == 45
assert nx.is_isomorphic(actual_graph, nx.complete_graph(expected_series_length))
def test_visibility_graph__concave_series__path_graph():
series = [-(i**2) for i in range(10)] # Slip Slidin' Away
expected_node_count = len(series)
actual_graph = nx.visibility_graph(series)
assert actual_graph.number_of_nodes() == expected_node_count
assert actual_graph.number_of_edges() == expected_node_count - 1
assert nx.is_isomorphic(actual_graph, nx.path_graph(expected_node_count))
def test_visibility_graph__flat_series__path_graph():
series = [0] * 10 # living in 1D flatland
expected_node_count = len(series)
actual_graph = nx.visibility_graph(series)
assert actual_graph.number_of_nodes() == expected_node_count
assert actual_graph.number_of_edges() == expected_node_count - 1
assert nx.is_isomorphic(actual_graph, nx.path_graph(expected_node_count))
def test_visibility_graph_cyclic_series():
series = list(itertools.islice(itertools.cycle((2, 1, 3)), 17)) # It's so bumpy!
expected_node_count = len(series)
actual_graph = nx.visibility_graph(series)
assert actual_graph.number_of_nodes() == expected_node_count
assert actual_graph.number_of_edges() == 25

View File

@ -0,0 +1,195 @@
import random
import pytest
import networkx as nx
from networkx.utils import arbitrary_element, graphs_equal
@pytest.mark.parametrize("prefix_tree_fn", (nx.prefix_tree, nx.prefix_tree_recursive))
def test_basic_prefix_tree(prefix_tree_fn):
# This example is from the Wikipedia article "Trie"
# <https://en.wikipedia.org/wiki/Trie>.
strings = ["a", "to", "tea", "ted", "ten", "i", "in", "inn"]
T = prefix_tree_fn(strings)
root, NIL = 0, -1
def source_label(v):
return T.nodes[v]["source"]
# First, we check that the tree has the expected
# structure. Recall that each node that corresponds to one of
# the input strings has an edge to the NIL node.
#
# Consider the three children at level 1 in the trie.
a, i, t = sorted(T[root], key=source_label)
# Check the 'a' branch.
assert len(T[a]) == 1
nil = arbitrary_element(T[a])
assert len(T[nil]) == 0
# Check the 'i' branch.
assert len(T[i]) == 2
nil, in_ = sorted(T[i], key=source_label)
assert len(T[nil]) == 0
assert len(T[in_]) == 2
nil, inn = sorted(T[in_], key=source_label)
assert len(T[nil]) == 0
assert len(T[inn]) == 1
nil = arbitrary_element(T[inn])
assert len(T[nil]) == 0
# Check the 't' branch.
te, to = sorted(T[t], key=source_label)
assert len(T[to]) == 1
nil = arbitrary_element(T[to])
assert len(T[nil]) == 0
tea, ted, ten = sorted(T[te], key=source_label)
assert len(T[tea]) == 1
assert len(T[ted]) == 1
assert len(T[ten]) == 1
nil = arbitrary_element(T[tea])
assert len(T[nil]) == 0
nil = arbitrary_element(T[ted])
assert len(T[nil]) == 0
nil = arbitrary_element(T[ten])
assert len(T[nil]) == 0
# Next, we check that the "sources" of each of the nodes is the
# rightmost letter in the string corresponding to the path to
# that node.
assert source_label(root) is None
assert source_label(a) == "a"
assert source_label(i) == "i"
assert source_label(t) == "t"
assert source_label(in_) == "n"
assert source_label(inn) == "n"
assert source_label(to) == "o"
assert source_label(te) == "e"
assert source_label(tea) == "a"
assert source_label(ted) == "d"
assert source_label(ten) == "n"
assert source_label(NIL) == "NIL"
@pytest.mark.parametrize(
"strings",
(
["a", "to", "tea", "ted", "ten", "i", "in", "inn"],
["ab", "abs", "ad"],
["ab", "abs", "ad", ""],
["distant", "disparaging", "distant", "diamond", "ruby"],
),
)
def test_implementations_consistent(strings):
"""Ensure results are consistent between prefix_tree implementations."""
assert graphs_equal(nx.prefix_tree(strings), nx.prefix_tree_recursive(strings))
def test_random_labeled_rooted_tree():
for i in range(1, 10):
t1 = nx.random_labeled_rooted_tree(i, seed=42)
t2 = nx.random_labeled_rooted_tree(i, seed=42)
assert nx.utils.misc.graphs_equal(t1, t2)
assert nx.is_tree(t1)
assert "root" in t1.graph
assert "roots" not in t1.graph
def test_random_labeled_tree_n_zero():
"""Tests if n = 0 then the NetworkXPointlessConcept exception is raised."""
with pytest.raises(nx.NetworkXPointlessConcept):
T = nx.random_labeled_tree(0, seed=1234)
with pytest.raises(nx.NetworkXPointlessConcept):
T = nx.random_labeled_rooted_tree(0, seed=1234)
def test_random_labeled_rooted_forest():
for i in range(1, 10):
t1 = nx.random_labeled_rooted_forest(i, seed=42)
t2 = nx.random_labeled_rooted_forest(i, seed=42)
assert nx.utils.misc.graphs_equal(t1, t2)
for c in nx.connected_components(t1):
assert nx.is_tree(t1.subgraph(c))
assert "root" not in t1.graph
assert "roots" in t1.graph
def test_random_labeled_rooted_forest_n_zero():
"""Tests generation of empty labeled forests."""
F = nx.random_labeled_rooted_forest(0, seed=1234)
assert len(F) == 0
assert len(F.graph["roots"]) == 0
def test_random_unlabeled_rooted_tree():
for i in range(1, 10):
t1 = nx.random_unlabeled_rooted_tree(i, seed=42)
t2 = nx.random_unlabeled_rooted_tree(i, seed=42)
assert nx.utils.misc.graphs_equal(t1, t2)
assert nx.is_tree(t1)
assert "root" in t1.graph
assert "roots" not in t1.graph
t = nx.random_unlabeled_rooted_tree(15, number_of_trees=10, seed=43)
random.seed(43)
s = nx.random_unlabeled_rooted_tree(15, number_of_trees=10, seed=random)
for i in range(10):
assert nx.utils.misc.graphs_equal(t[i], s[i])
assert nx.is_tree(t[i])
assert "root" in t[i].graph
assert "roots" not in t[i].graph
def test_random_unlabeled_tree_n_zero():
"""Tests if n = 0 then the NetworkXPointlessConcept exception is raised."""
with pytest.raises(nx.NetworkXPointlessConcept):
T = nx.random_unlabeled_tree(0, seed=1234)
with pytest.raises(nx.NetworkXPointlessConcept):
T = nx.random_unlabeled_rooted_tree(0, seed=1234)
def test_random_unlabeled_rooted_forest():
with pytest.raises(ValueError):
nx.random_unlabeled_rooted_forest(10, q=0, seed=42)
for i in range(1, 10):
for q in range(1, i + 1):
t1 = nx.random_unlabeled_rooted_forest(i, q=q, seed=42)
t2 = nx.random_unlabeled_rooted_forest(i, q=q, seed=42)
assert nx.utils.misc.graphs_equal(t1, t2)
for c in nx.connected_components(t1):
assert nx.is_tree(t1.subgraph(c))
assert len(c) <= q
assert "root" not in t1.graph
assert "roots" in t1.graph
t = nx.random_unlabeled_rooted_forest(15, number_of_forests=10, seed=43)
random.seed(43)
s = nx.random_unlabeled_rooted_forest(15, number_of_forests=10, seed=random)
for i in range(10):
assert nx.utils.misc.graphs_equal(t[i], s[i])
for c in nx.connected_components(t[i]):
assert nx.is_tree(t[i].subgraph(c))
assert "root" not in t[i].graph
assert "roots" in t[i].graph
def test_random_unlabeled_forest_n_zero():
"""Tests generation of empty unlabeled forests."""
F = nx.random_unlabeled_rooted_forest(0, seed=1234)
assert len(F) == 0
assert len(F.graph["roots"]) == 0
def test_random_unlabeled_tree():
for i in range(1, 10):
t1 = nx.random_unlabeled_tree(i, seed=42)
t2 = nx.random_unlabeled_tree(i, seed=42)
assert nx.utils.misc.graphs_equal(t1, t2)
assert nx.is_tree(t1)
assert "root" not in t1.graph
assert "roots" not in t1.graph
t = nx.random_unlabeled_tree(10, number_of_trees=10, seed=43)
random.seed(43)
s = nx.random_unlabeled_tree(10, number_of_trees=10, seed=random)
for i in range(10):
assert nx.utils.misc.graphs_equal(t[i], s[i])
assert nx.is_tree(t[i])
assert "root" not in t[i].graph
assert "roots" not in t[i].graph

View File

@ -0,0 +1,15 @@
"""Unit tests for the :mod:`networkx.generators.triads` module."""
import pytest
from networkx import triad_graph
def test_triad_graph():
G = triad_graph("030T")
assert [tuple(e) for e in ("ab", "ac", "cb")] == sorted(G.edges())
def test_invalid_name():
with pytest.raises(ValueError):
triad_graph("bogus")