123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- """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.watts_strogatz_graph(10, 2, 0.25, seed)
- assert len(G) == 10
- assert G.number_of_edges() == 10
- G = nx.connected_watts_strogatz_graph(10, 2, 0.1, tries=10, seed=seed)
- assert len(G) == 10
- assert G.number_of_edges() == 10
- pytest.raises(
- nx.NetworkXError, nx.connected_watts_strogatz_graph, 10, 2, 0.1, tries=0
- )
- G = nx.watts_strogatz_graph(10, 4, 0.25, seed)
- assert len(G) == 10
- assert G.number_of_edges() == 20
- G = nx.newman_watts_strogatz_graph(10, 2, 0.0, seed)
- assert len(G) == 10
- assert G.number_of_edges() == 10
- G = nx.newman_watts_strogatz_graph(10, 4, 0.25, seed)
- assert len(G) == 10
- assert G.number_of_edges() >= 20
- 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
|