Fixed database typo and removed unnecessary class identifier.

This commit is contained in:
Batuhan Berk Başoğlu 2020-10-14 10:10:37 -04:00
parent 00ad49a143
commit 45fb349a7d
5098 changed files with 952558 additions and 85 deletions

View file

@ -0,0 +1,121 @@
import pytest
import networkx as nx
from networkx.algorithms import bipartite
class TestBipartiteBasic:
def test_is_bipartite(self):
assert bipartite.is_bipartite(nx.path_graph(4))
assert bipartite.is_bipartite(nx.DiGraph([(1, 0)]))
assert not bipartite.is_bipartite(nx.complete_graph(3))
def test_bipartite_color(self):
G = nx.path_graph(4)
c = bipartite.color(G)
assert c == {0: 1, 1: 0, 2: 1, 3: 0}
def test_not_bipartite_color(self):
with pytest.raises(nx.NetworkXError):
c = bipartite.color(nx.complete_graph(4))
def test_bipartite_directed(self):
G = bipartite.random_graph(10, 10, 0.1, directed=True)
assert bipartite.is_bipartite(G)
def test_bipartite_sets(self):
G = nx.path_graph(4)
X, Y = bipartite.sets(G)
assert X == {0, 2}
assert Y == {1, 3}
def test_bipartite_sets_directed(self):
G = nx.path_graph(4)
D = G.to_directed()
X, Y = bipartite.sets(D)
assert X == {0, 2}
assert Y == {1, 3}
def test_bipartite_sets_given_top_nodes(self):
G = nx.path_graph(4)
top_nodes = [0, 2]
X, Y = bipartite.sets(G, top_nodes)
assert X == {0, 2}
assert Y == {1, 3}
def test_bipartite_sets_disconnected(self):
with pytest.raises(nx.AmbiguousSolution):
G = nx.path_graph(4)
G.add_edges_from([(5, 6), (6, 7)])
X, Y = bipartite.sets(G)
def test_is_bipartite_node_set(self):
G = nx.path_graph(4)
assert bipartite.is_bipartite_node_set(G, [0, 2])
assert bipartite.is_bipartite_node_set(G, [1, 3])
assert not bipartite.is_bipartite_node_set(G, [1, 2])
G.add_edge(10, 20)
assert bipartite.is_bipartite_node_set(G, [0, 2, 10])
assert bipartite.is_bipartite_node_set(G, [0, 2, 20])
assert bipartite.is_bipartite_node_set(G, [1, 3, 10])
assert bipartite.is_bipartite_node_set(G, [1, 3, 20])
def test_bipartite_density(self):
G = nx.path_graph(5)
X, Y = bipartite.sets(G)
density = float(len(list(G.edges()))) / (len(X) * len(Y))
assert bipartite.density(G, X) == density
D = nx.DiGraph(G.edges())
assert bipartite.density(D, X) == density / 2.0
assert bipartite.density(nx.Graph(), {}) == 0.0
def test_bipartite_degrees(self):
G = nx.path_graph(5)
X = {1, 3}
Y = {0, 2, 4}
u, d = bipartite.degrees(G, Y)
assert dict(u) == {1: 2, 3: 2}
assert dict(d) == {0: 1, 2: 2, 4: 1}
def test_bipartite_weighted_degrees(self):
G = nx.path_graph(5)
G.add_edge(0, 1, weight=0.1, other=0.2)
X = {1, 3}
Y = {0, 2, 4}
u, d = bipartite.degrees(G, Y, weight="weight")
assert dict(u) == {1: 1.1, 3: 2}
assert dict(d) == {0: 0.1, 2: 2, 4: 1}
u, d = bipartite.degrees(G, Y, weight="other")
assert dict(u) == {1: 1.2, 3: 2}
assert dict(d) == {0: 0.2, 2: 2, 4: 1}
def test_biadjacency_matrix_weight(self):
scipy = pytest.importorskip("scipy")
G = nx.path_graph(5)
G.add_edge(0, 1, weight=2, other=4)
X = [1, 3]
Y = [0, 2, 4]
M = bipartite.biadjacency_matrix(G, X, weight="weight")
assert M[0, 0] == 2
M = bipartite.biadjacency_matrix(G, X, weight="other")
assert M[0, 0] == 4
def test_biadjacency_matrix(self):
scipy = pytest.importorskip("scipy")
tops = [2, 5, 10]
bots = [5, 10, 15]
for i in range(len(tops)):
G = bipartite.random_graph(tops[i], bots[i], 0.2)
top = [n for n, d in G.nodes(data=True) if d["bipartite"] == 0]
M = bipartite.biadjacency_matrix(G, top)
assert M.shape[0] == tops[i]
assert M.shape[1] == bots[i]
def test_biadjacency_matrix_order(self):
scipy = pytest.importorskip("scipy")
G = nx.path_graph(5)
G.add_edge(0, 1, weight=2)
X = [3, 1]
Y = [4, 2, 0]
M = bipartite.biadjacency_matrix(G, X, Y, weight="weight")
assert M[1, 2] == 2

View file

@ -0,0 +1,175 @@
import networkx as nx
from networkx.algorithms import bipartite
from networkx.testing import almost_equal
class TestBipartiteCentrality:
@classmethod
def setup_class(cls):
cls.P4 = nx.path_graph(4)
cls.K3 = nx.complete_bipartite_graph(3, 3)
cls.C4 = nx.cycle_graph(4)
cls.davis = nx.davis_southern_women_graph()
cls.top_nodes = [
n for n, d in cls.davis.nodes(data=True) if d["bipartite"] == 0
]
def test_degree_centrality(self):
d = bipartite.degree_centrality(self.P4, [1, 3])
answer = {0: 0.5, 1: 1.0, 2: 1.0, 3: 0.5}
assert d == answer
d = bipartite.degree_centrality(self.K3, [0, 1, 2])
answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0}
assert d == answer
d = bipartite.degree_centrality(self.C4, [0, 2])
answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0}
assert d == answer
def test_betweenness_centrality(self):
c = bipartite.betweenness_centrality(self.P4, [1, 3])
answer = {0: 0.0, 1: 1.0, 2: 1.0, 3: 0.0}
assert c == answer
c = bipartite.betweenness_centrality(self.K3, [0, 1, 2])
answer = {0: 0.125, 1: 0.125, 2: 0.125, 3: 0.125, 4: 0.125, 5: 0.125}
assert c == answer
c = bipartite.betweenness_centrality(self.C4, [0, 2])
answer = {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25}
assert c == answer
def test_closeness_centrality(self):
c = bipartite.closeness_centrality(self.P4, [1, 3])
answer = {0: 2.0 / 3, 1: 1.0, 2: 1.0, 3: 2.0 / 3}
assert c == answer
c = bipartite.closeness_centrality(self.K3, [0, 1, 2])
answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0}
assert c == answer
c = bipartite.closeness_centrality(self.C4, [0, 2])
answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0}
assert c == answer
G = nx.Graph()
G.add_node(0)
G.add_node(1)
c = bipartite.closeness_centrality(G, [0])
assert c == {1: 0.0}
c = bipartite.closeness_centrality(G, [1])
assert c == {1: 0.0}
def test_davis_degree_centrality(self):
G = self.davis
deg = bipartite.degree_centrality(G, self.top_nodes)
answer = {
"E8": 0.78,
"E9": 0.67,
"E7": 0.56,
"Nora Fayette": 0.57,
"Evelyn Jefferson": 0.57,
"Theresa Anderson": 0.57,
"E6": 0.44,
"Sylvia Avondale": 0.50,
"Laura Mandeville": 0.50,
"Brenda Rogers": 0.50,
"Katherina Rogers": 0.43,
"E5": 0.44,
"Helen Lloyd": 0.36,
"E3": 0.33,
"Ruth DeSand": 0.29,
"Verne Sanderson": 0.29,
"E12": 0.33,
"Myra Liddel": 0.29,
"E11": 0.22,
"Eleanor Nye": 0.29,
"Frances Anderson": 0.29,
"Pearl Oglethorpe": 0.21,
"E4": 0.22,
"Charlotte McDowd": 0.29,
"E10": 0.28,
"Olivia Carleton": 0.14,
"Flora Price": 0.14,
"E2": 0.17,
"E1": 0.17,
"Dorothy Murchison": 0.14,
"E13": 0.17,
"E14": 0.17,
}
for node, value in answer.items():
assert almost_equal(value, deg[node], places=2)
def test_davis_betweenness_centrality(self):
G = self.davis
bet = bipartite.betweenness_centrality(G, self.top_nodes)
answer = {
"E8": 0.24,
"E9": 0.23,
"E7": 0.13,
"Nora Fayette": 0.11,
"Evelyn Jefferson": 0.10,
"Theresa Anderson": 0.09,
"E6": 0.07,
"Sylvia Avondale": 0.07,
"Laura Mandeville": 0.05,
"Brenda Rogers": 0.05,
"Katherina Rogers": 0.05,
"E5": 0.04,
"Helen Lloyd": 0.04,
"E3": 0.02,
"Ruth DeSand": 0.02,
"Verne Sanderson": 0.02,
"E12": 0.02,
"Myra Liddel": 0.02,
"E11": 0.02,
"Eleanor Nye": 0.01,
"Frances Anderson": 0.01,
"Pearl Oglethorpe": 0.01,
"E4": 0.01,
"Charlotte McDowd": 0.01,
"E10": 0.01,
"Olivia Carleton": 0.01,
"Flora Price": 0.01,
"E2": 0.00,
"E1": 0.00,
"Dorothy Murchison": 0.00,
"E13": 0.00,
"E14": 0.00,
}
for node, value in answer.items():
assert almost_equal(value, bet[node], places=2)
def test_davis_closeness_centrality(self):
G = self.davis
clos = bipartite.closeness_centrality(G, self.top_nodes)
answer = {
"E8": 0.85,
"E9": 0.79,
"E7": 0.73,
"Nora Fayette": 0.80,
"Evelyn Jefferson": 0.80,
"Theresa Anderson": 0.80,
"E6": 0.69,
"Sylvia Avondale": 0.77,
"Laura Mandeville": 0.73,
"Brenda Rogers": 0.73,
"Katherina Rogers": 0.73,
"E5": 0.59,
"Helen Lloyd": 0.73,
"E3": 0.56,
"Ruth DeSand": 0.71,
"Verne Sanderson": 0.71,
"E12": 0.56,
"Myra Liddel": 0.69,
"E11": 0.54,
"Eleanor Nye": 0.67,
"Frances Anderson": 0.67,
"Pearl Oglethorpe": 0.67,
"E4": 0.54,
"Charlotte McDowd": 0.60,
"E10": 0.55,
"Olivia Carleton": 0.59,
"Flora Price": 0.59,
"E2": 0.52,
"E1": 0.52,
"Dorothy Murchison": 0.65,
"E13": 0.52,
"E14": 0.52,
}
for node, value in answer.items():
assert almost_equal(value, clos[node], places=2)

View file

@ -0,0 +1,83 @@
import networkx as nx
import pytest
from networkx.algorithms.bipartite.cluster import cc_dot, cc_min, cc_max
import networkx.algorithms.bipartite as bipartite
def test_pairwise_bipartite_cc_functions():
# Test functions for different kinds of bipartite clustering coefficients
# between pairs of nodes using 3 example graphs from figure 5 p. 40
# Latapy et al (2008)
G1 = nx.Graph([(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7)])
G2 = nx.Graph([(0, 2), (0, 3), (0, 4), (1, 3), (1, 4), (1, 5)])
G3 = nx.Graph(
[(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9)]
)
result = {
0: [1 / 3.0, 2 / 3.0, 2 / 5.0],
1: [1 / 2.0, 2 / 3.0, 2 / 3.0],
2: [2 / 8.0, 2 / 5.0, 2 / 5.0],
}
for i, G in enumerate([G1, G2, G3]):
assert bipartite.is_bipartite(G)
assert cc_dot(set(G[0]), set(G[1])) == result[i][0]
assert cc_min(set(G[0]), set(G[1])) == result[i][1]
assert cc_max(set(G[0]), set(G[1])) == result[i][2]
def test_star_graph():
G = nx.star_graph(3)
# all modes are the same
answer = {0: 0, 1: 1, 2: 1, 3: 1}
assert bipartite.clustering(G, mode="dot") == answer
assert bipartite.clustering(G, mode="min") == answer
assert bipartite.clustering(G, mode="max") == answer
def test_not_bipartite():
with pytest.raises(nx.NetworkXError):
bipartite.clustering(nx.complete_graph(4))
def test_bad_mode():
with pytest.raises(nx.NetworkXError):
bipartite.clustering(nx.path_graph(4), mode="foo")
def test_path_graph():
G = nx.path_graph(4)
answer = {0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5}
assert bipartite.clustering(G, mode="dot") == answer
assert bipartite.clustering(G, mode="max") == answer
answer = {0: 1, 1: 1, 2: 1, 3: 1}
assert bipartite.clustering(G, mode="min") == answer
def test_average_path_graph():
G = nx.path_graph(4)
assert bipartite.average_clustering(G, mode="dot") == 0.5
assert bipartite.average_clustering(G, mode="max") == 0.5
assert bipartite.average_clustering(G, mode="min") == 1
def test_ra_clustering_davis():
G = nx.davis_southern_women_graph()
cc4 = round(bipartite.robins_alexander_clustering(G), 3)
assert cc4 == 0.468
def test_ra_clustering_square():
G = nx.path_graph(4)
G.add_edge(0, 3)
assert bipartite.robins_alexander_clustering(G) == 1.0
def test_ra_clustering_zero():
G = nx.Graph()
assert bipartite.robins_alexander_clustering(G) == 0
G.add_nodes_from(range(4))
assert bipartite.robins_alexander_clustering(G) == 0
G.add_edges_from([(0, 1), (2, 3), (3, 4)])
assert bipartite.robins_alexander_clustering(G) == 0
G.add_edge(1, 2)
assert bipartite.robins_alexander_clustering(G) == 0

View file

@ -0,0 +1,33 @@
import networkx as nx
import networkx.algorithms.bipartite as bipartite
class TestMinEdgeCover:
"""Tests for :func:`networkx.algorithms.bipartite.min_edge_cover`"""
def test_empty_graph(self):
G = nx.Graph()
assert bipartite.min_edge_cover(G) == set()
def test_graph_single_edge(self):
G = nx.Graph()
G.add_edge(0, 1)
assert bipartite.min_edge_cover(G) == {(0, 1), (1, 0)}
def test_bipartite_default(self):
G = nx.Graph()
G.add_nodes_from([1, 2, 3, 4], bipartite=0)
G.add_nodes_from(["a", "b", "c"], bipartite=1)
G.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")])
min_cover = bipartite.min_edge_cover(G)
assert nx.is_edge_cover(G, min_cover)
assert len(min_cover) == 8
def test_bipartite_explicit(self):
G = nx.Graph()
G.add_nodes_from([1, 2, 3, 4], bipartite=0)
G.add_nodes_from(["a", "b", "c"], bipartite=1)
G.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")])
min_cover = bipartite.min_edge_cover(G, bipartite.eppstein_matching)
assert nx.is_edge_cover(G, min_cover)
assert len(min_cover) == 8

View file

@ -0,0 +1,191 @@
"""
Unit tests for bipartite edgelists.
"""
import pytest
import io
import tempfile
import os
import networkx as nx
from networkx.testing import assert_edges_equal, assert_nodes_equal, assert_graphs_equal
from networkx.algorithms import bipartite
class TestEdgelist:
@classmethod
def setup_class(cls):
cls.G = nx.Graph(name="test")
e = [("a", "b"), ("b", "c"), ("c", "d"), ("d", "e"), ("e", "f"), ("a", "f")]
cls.G.add_edges_from(e)
cls.G.add_nodes_from(["a", "c", "e"], bipartite=0)
cls.G.add_nodes_from(["b", "d", "f"], bipartite=1)
cls.G.add_node("g", bipartite=0)
cls.DG = nx.DiGraph(cls.G)
cls.MG = nx.MultiGraph()
cls.MG.add_edges_from([(1, 2), (1, 2), (1, 2)])
cls.MG.add_node(1, bipartite=0)
cls.MG.add_node(2, bipartite=1)
def test_read_edgelist_1(self):
s = b"""\
# comment line
1 2
# comment line
2 3
"""
bytesIO = io.BytesIO(s)
G = bipartite.read_edgelist(bytesIO, nodetype=int)
assert_edges_equal(G.edges(), [(1, 2), (2, 3)])
def test_read_edgelist_3(self):
s = b"""\
# comment line
1 2 {'weight':2.0}
# comment line
2 3 {'weight':3.0}
"""
bytesIO = io.BytesIO(s)
G = bipartite.read_edgelist(bytesIO, nodetype=int, data=False)
assert_edges_equal(G.edges(), [(1, 2), (2, 3)])
bytesIO = io.BytesIO(s)
G = bipartite.read_edgelist(bytesIO, nodetype=int, data=True)
assert_edges_equal(
G.edges(data=True), [(1, 2, {"weight": 2.0}), (2, 3, {"weight": 3.0})]
)
def test_write_edgelist_1(self):
fh = io.BytesIO()
G = nx.Graph()
G.add_edges_from([(1, 2), (2, 3)])
G.add_node(1, bipartite=0)
G.add_node(2, bipartite=1)
G.add_node(3, bipartite=0)
bipartite.write_edgelist(G, fh, data=False)
fh.seek(0)
assert fh.read() == b"1 2\n3 2\n"
def test_write_edgelist_2(self):
fh = io.BytesIO()
G = nx.Graph()
G.add_edges_from([(1, 2), (2, 3)])
G.add_node(1, bipartite=0)
G.add_node(2, bipartite=1)
G.add_node(3, bipartite=0)
bipartite.write_edgelist(G, fh, data=True)
fh.seek(0)
assert fh.read() == b"1 2 {}\n3 2 {}\n"
def test_write_edgelist_3(self):
fh = io.BytesIO()
G = nx.Graph()
G.add_edge(1, 2, weight=2.0)
G.add_edge(2, 3, weight=3.0)
G.add_node(1, bipartite=0)
G.add_node(2, bipartite=1)
G.add_node(3, bipartite=0)
bipartite.write_edgelist(G, fh, data=True)
fh.seek(0)
assert fh.read() == b"1 2 {'weight': 2.0}\n3 2 {'weight': 3.0}\n"
def test_write_edgelist_4(self):
fh = io.BytesIO()
G = nx.Graph()
G.add_edge(1, 2, weight=2.0)
G.add_edge(2, 3, weight=3.0)
G.add_node(1, bipartite=0)
G.add_node(2, bipartite=1)
G.add_node(3, bipartite=0)
bipartite.write_edgelist(G, fh, data=[("weight")])
fh.seek(0)
assert fh.read() == b"1 2 2.0\n3 2 3.0\n"
def test_unicode(self):
G = nx.Graph()
name1 = chr(2344) + chr(123) + chr(6543)
name2 = chr(5543) + chr(1543) + chr(324)
G.add_edge(name1, "Radiohead", **{name2: 3})
G.add_node(name1, bipartite=0)
G.add_node("Radiohead", bipartite=1)
fd, fname = tempfile.mkstemp()
bipartite.write_edgelist(G, fname)
H = bipartite.read_edgelist(fname)
assert_graphs_equal(G, H)
os.close(fd)
os.unlink(fname)
def test_latin1_issue(self):
G = nx.Graph()
name1 = chr(2344) + chr(123) + chr(6543)
name2 = chr(5543) + chr(1543) + chr(324)
G.add_edge(name1, "Radiohead", **{name2: 3})
G.add_node(name1, bipartite=0)
G.add_node("Radiohead", bipartite=1)
fd, fname = tempfile.mkstemp()
pytest.raises(
UnicodeEncodeError, bipartite.write_edgelist, G, fname, encoding="latin-1"
)
os.close(fd)
os.unlink(fname)
def test_latin1(self):
G = nx.Graph()
name1 = "Bj" + chr(246) + "rk"
name2 = chr(220) + "ber"
G.add_edge(name1, "Radiohead", **{name2: 3})
G.add_node(name1, bipartite=0)
G.add_node("Radiohead", bipartite=1)
fd, fname = tempfile.mkstemp()
bipartite.write_edgelist(G, fname, encoding="latin-1")
H = bipartite.read_edgelist(fname, encoding="latin-1")
assert_graphs_equal(G, H)
os.close(fd)
os.unlink(fname)
def test_edgelist_graph(self):
G = self.G
(fd, fname) = tempfile.mkstemp()
bipartite.write_edgelist(G, fname)
H = bipartite.read_edgelist(fname)
H2 = bipartite.read_edgelist(fname)
assert H != H2 # they should be different graphs
G.remove_node("g") # isolated nodes are not written in edgelist
assert_nodes_equal(list(H), list(G))
assert_edges_equal(list(H.edges()), list(G.edges()))
os.close(fd)
os.unlink(fname)
def test_edgelist_integers(self):
G = nx.convert_node_labels_to_integers(self.G)
(fd, fname) = tempfile.mkstemp()
bipartite.write_edgelist(G, fname)
H = bipartite.read_edgelist(fname, nodetype=int)
# isolated nodes are not written in edgelist
G.remove_nodes_from(list(nx.isolates(G)))
assert_nodes_equal(list(H), list(G))
assert_edges_equal(list(H.edges()), list(G.edges()))
os.close(fd)
os.unlink(fname)
def test_edgelist_multigraph(self):
G = self.MG
(fd, fname) = tempfile.mkstemp()
bipartite.write_edgelist(G, fname)
H = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph())
H2 = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph())
assert H != H2 # they should be different graphs
assert_nodes_equal(list(H), list(G))
assert_edges_equal(list(H.edges()), list(G.edges()))
os.close(fd)
os.unlink(fname)
def test_empty_digraph(self):
with pytest.raises(nx.NetworkXNotImplemented):
bytesIO = io.BytesIO()
bipartite.write_edgelist(nx.DiGraph(), bytesIO)
def test_raise_attribute(self):
with pytest.raises(AttributeError):
G = nx.path_graph(4)
bytesIO = io.BytesIO()
bipartite.write_edgelist(G, bytesIO)

View file

@ -0,0 +1,399 @@
import pytest
import networkx as nx
from ..generators import (
alternating_havel_hakimi_graph,
complete_bipartite_graph,
configuration_model,
gnmk_random_graph,
havel_hakimi_graph,
preferential_attachment_graph,
random_graph,
reverse_havel_hakimi_graph,
)
"""
Generators - Bipartite
----------------------
"""
class TestGeneratorsBipartite:
def test_complete_bipartite_graph(self):
G = complete_bipartite_graph(0, 0)
assert nx.is_isomorphic(G, nx.null_graph())
for i in [1, 5]:
G = complete_bipartite_graph(i, 0)
assert nx.is_isomorphic(G, nx.empty_graph(i))
G = complete_bipartite_graph(0, i)
assert nx.is_isomorphic(G, nx.empty_graph(i))
G = complete_bipartite_graph(2, 2)
assert nx.is_isomorphic(G, nx.cycle_graph(4))
G = complete_bipartite_graph(1, 5)
assert nx.is_isomorphic(G, nx.star_graph(5))
G = complete_bipartite_graph(5, 1)
assert nx.is_isomorphic(G, nx.star_graph(5))
# complete_bipartite_graph(m1,m2) is a connected graph with
# m1+m2 nodes and m1*m2 edges
for m1, m2 in [(5, 11), (7, 3)]:
G = complete_bipartite_graph(m1, m2)
assert nx.number_of_nodes(G) == m1 + m2
assert nx.number_of_edges(G) == m1 * m2
pytest.raises(
nx.NetworkXError, complete_bipartite_graph, 7, 3, create_using=nx.DiGraph
)
pytest.raises(
nx.NetworkXError, complete_bipartite_graph, 7, 3, create_using=nx.DiGraph
)
pytest.raises(
nx.NetworkXError,
complete_bipartite_graph,
7,
3,
create_using=nx.MultiDiGraph,
)
mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph)
assert mG.is_multigraph()
assert sorted(mG.edges()) == sorted(G.edges())
mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph)
assert mG.is_multigraph()
assert sorted(mG.edges()) == sorted(G.edges())
mG = complete_bipartite_graph(7, 3) # default to Graph
assert sorted(mG.edges()) == sorted(G.edges())
assert not mG.is_multigraph()
assert not mG.is_directed()
# specify nodes rather than number of nodes
G = complete_bipartite_graph([1, 2], ["a", "b"])
has_edges = (
G.has_edge(1, "a")
& G.has_edge(1, "b")
& G.has_edge(2, "a")
& G.has_edge(2, "b")
)
assert has_edges
assert G.size() == 4
def test_configuration_model(self):
aseq = []
bseq = []
G = configuration_model(aseq, bseq)
assert len(G) == 0
aseq = [0, 0]
bseq = [0, 0]
G = configuration_model(aseq, bseq)
assert len(G) == 4
assert G.number_of_edges() == 0
aseq = [3, 3, 3, 3]
bseq = [2, 2, 2, 2, 2]
pytest.raises(nx.NetworkXError, configuration_model, aseq, bseq)
aseq = [3, 3, 3, 3]
bseq = [2, 2, 2, 2, 2, 2]
G = configuration_model(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 2, 2, 2]
bseq = [3, 3, 3, 3]
G = configuration_model(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 1, 1, 1]
bseq = [3, 3, 3]
G = configuration_model(aseq, bseq)
assert G.is_multigraph()
assert not G.is_directed()
assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3]
GU = nx.project(nx.Graph(G), range(len(aseq)))
assert GU.number_of_nodes() == 6
GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq)))
assert GD.number_of_nodes() == 3
G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph)
assert not G.is_multigraph()
assert not G.is_directed()
pytest.raises(
nx.NetworkXError, configuration_model, aseq, bseq, create_using=nx.DiGraph()
)
pytest.raises(
nx.NetworkXError, configuration_model, aseq, bseq, create_using=nx.DiGraph
)
pytest.raises(
nx.NetworkXError,
configuration_model,
aseq,
bseq,
create_using=nx.MultiDiGraph,
)
def test_havel_hakimi_graph(self):
aseq = []
bseq = []
G = havel_hakimi_graph(aseq, bseq)
assert len(G) == 0
aseq = [0, 0]
bseq = [0, 0]
G = havel_hakimi_graph(aseq, bseq)
assert len(G) == 4
assert G.number_of_edges() == 0
aseq = [3, 3, 3, 3]
bseq = [2, 2, 2, 2, 2]
pytest.raises(nx.NetworkXError, havel_hakimi_graph, aseq, bseq)
bseq = [2, 2, 2, 2, 2, 2]
G = havel_hakimi_graph(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 2, 2, 2]
bseq = [3, 3, 3, 3]
G = havel_hakimi_graph(aseq, bseq)
assert G.is_multigraph()
assert not G.is_directed()
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
GU = nx.project(nx.Graph(G), range(len(aseq)))
assert GU.number_of_nodes() == 6
GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq)))
assert GD.number_of_nodes() == 4
G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph)
assert not G.is_multigraph()
assert not G.is_directed()
pytest.raises(
nx.NetworkXError, havel_hakimi_graph, aseq, bseq, create_using=nx.DiGraph
)
pytest.raises(
nx.NetworkXError, havel_hakimi_graph, aseq, bseq, create_using=nx.DiGraph
)
pytest.raises(
nx.NetworkXError,
havel_hakimi_graph,
aseq,
bseq,
create_using=nx.MultiDiGraph,
)
def test_reverse_havel_hakimi_graph(self):
aseq = []
bseq = []
G = reverse_havel_hakimi_graph(aseq, bseq)
assert len(G) == 0
aseq = [0, 0]
bseq = [0, 0]
G = reverse_havel_hakimi_graph(aseq, bseq)
assert len(G) == 4
assert G.number_of_edges() == 0
aseq = [3, 3, 3, 3]
bseq = [2, 2, 2, 2, 2]
pytest.raises(nx.NetworkXError, reverse_havel_hakimi_graph, aseq, bseq)
bseq = [2, 2, 2, 2, 2, 2]
G = reverse_havel_hakimi_graph(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 2, 2, 2]
bseq = [3, 3, 3, 3]
G = reverse_havel_hakimi_graph(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 1, 1, 1]
bseq = [3, 3, 3]
G = reverse_havel_hakimi_graph(aseq, bseq)
assert G.is_multigraph()
assert not G.is_directed()
assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3]
GU = nx.project(nx.Graph(G), range(len(aseq)))
assert GU.number_of_nodes() == 6
GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq)))
assert GD.number_of_nodes() == 3
G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph)
assert not G.is_multigraph()
assert not G.is_directed()
pytest.raises(
nx.NetworkXError,
reverse_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.DiGraph,
)
pytest.raises(
nx.NetworkXError,
reverse_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.DiGraph,
)
pytest.raises(
nx.NetworkXError,
reverse_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.MultiDiGraph,
)
def test_alternating_havel_hakimi_graph(self):
aseq = []
bseq = []
G = alternating_havel_hakimi_graph(aseq, bseq)
assert len(G) == 0
aseq = [0, 0]
bseq = [0, 0]
G = alternating_havel_hakimi_graph(aseq, bseq)
assert len(G) == 4
assert G.number_of_edges() == 0
aseq = [3, 3, 3, 3]
bseq = [2, 2, 2, 2, 2]
pytest.raises(nx.NetworkXError, alternating_havel_hakimi_graph, aseq, bseq)
bseq = [2, 2, 2, 2, 2, 2]
G = alternating_havel_hakimi_graph(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 2, 2, 2]
bseq = [3, 3, 3, 3]
G = alternating_havel_hakimi_graph(aseq, bseq)
assert sorted(d for n, d in G.degree()) == [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]
aseq = [2, 2, 2, 1, 1, 1]
bseq = [3, 3, 3]
G = alternating_havel_hakimi_graph(aseq, bseq)
assert G.is_multigraph()
assert not G.is_directed()
assert sorted(d for n, d in G.degree()) == [1, 1, 1, 2, 2, 2, 3, 3, 3]
GU = nx.project(nx.Graph(G), range(len(aseq)))
assert GU.number_of_nodes() == 6
GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq)))
assert GD.number_of_nodes() == 3
G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph)
assert not G.is_multigraph()
assert not G.is_directed()
pytest.raises(
nx.NetworkXError,
alternating_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.DiGraph,
)
pytest.raises(
nx.NetworkXError,
alternating_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.DiGraph,
)
pytest.raises(
nx.NetworkXError,
alternating_havel_hakimi_graph,
aseq,
bseq,
create_using=nx.MultiDiGraph,
)
def test_preferential_attachment(self):
aseq = [3, 2, 1, 1]
G = preferential_attachment_graph(aseq, 0.5)
assert G.is_multigraph()
assert not G.is_directed()
G = preferential_attachment_graph(aseq, 0.5, create_using=nx.Graph)
assert not G.is_multigraph()
assert not G.is_directed()
pytest.raises(
nx.NetworkXError,
preferential_attachment_graph,
aseq,
0.5,
create_using=nx.DiGraph(),
)
pytest.raises(
nx.NetworkXError,
preferential_attachment_graph,
aseq,
0.5,
create_using=nx.DiGraph(),
)
pytest.raises(
nx.NetworkXError,
preferential_attachment_graph,
aseq,
0.5,
create_using=nx.DiGraph(),
)
def test_random_graph(self):
n = 10
m = 20
G = random_graph(n, m, 0.9)
assert len(G) == 30
assert nx.is_bipartite(G)
X, Y = nx.algorithms.bipartite.sets(G)
assert set(range(n)) == X
assert set(range(n, n + m)) == Y
def test_random_digraph(self):
n = 10
m = 20
G = random_graph(n, m, 0.9, directed=True)
assert len(G) == 30
assert nx.is_bipartite(G)
X, Y = nx.algorithms.bipartite.sets(G)
assert set(range(n)) == X
assert set(range(n, n + m)) == Y
def test_gnmk_random_graph(self):
n = 10
m = 20
edges = 100
# set seed because sometimes it is not connected
# which raises an error in bipartite.sets(G) below.
G = gnmk_random_graph(n, m, edges, seed=1234)
assert len(G) == n + m
assert nx.is_bipartite(G)
X, Y = nx.algorithms.bipartite.sets(G)
# print(X)
assert set(range(n)) == X
assert set(range(n, n + m)) == Y
assert edges == len(list(G.edges()))
def test_gnmk_random_graph_complete(self):
n = 10
m = 20
edges = 200
G = gnmk_random_graph(n, m, edges)
assert len(G) == n + m
assert nx.is_bipartite(G)
X, Y = nx.algorithms.bipartite.sets(G)
# print(X)
assert set(range(n)) == X
assert set(range(n, n + m)) == Y
assert edges == len(list(G.edges()))

View file

@ -0,0 +1,316 @@
"""Unit tests for the :mod:`networkx.algorithms.bipartite.matching` module."""
import itertools
import networkx as nx
import pytest
from networkx.algorithms.bipartite.matching import eppstein_matching
from networkx.algorithms.bipartite.matching import hopcroft_karp_matching
from networkx.algorithms.bipartite.matching import maximum_matching
from networkx.algorithms.bipartite.matching import minimum_weight_full_matching
from networkx.algorithms.bipartite.matching import to_vertex_cover
class TestMatching:
"""Tests for bipartite matching algorithms."""
def setup(self):
"""Creates a bipartite graph for use in testing matching algorithms.
The bipartite graph has a maximum cardinality matching that leaves
vertex 1 and vertex 10 unmatched. The first six numbers are the left
vertices and the next six numbers are the right vertices.
"""
self.simple_graph = nx.complete_bipartite_graph(2, 3)
self.simple_solution = {0: 2, 1: 3, 2: 0, 3: 1}
edges = [(0, 7), (0, 8), (2, 6), (2, 9), (3, 8), (4, 8), (4, 9), (5, 11)]
self.top_nodes = set(range(6))
self.graph = nx.Graph()
self.graph.add_nodes_from(range(12))
self.graph.add_edges_from(edges)
# Example bipartite graph from issue 2127
G = nx.Graph()
G.add_nodes_from(
[
(1, "C"),
(1, "B"),
(0, "G"),
(1, "F"),
(1, "E"),
(0, "C"),
(1, "D"),
(1, "I"),
(0, "A"),
(0, "D"),
(0, "F"),
(0, "E"),
(0, "H"),
(1, "G"),
(1, "A"),
(0, "I"),
(0, "B"),
(1, "H"),
]
)
G.add_edge((1, "C"), (0, "A"))
G.add_edge((1, "B"), (0, "A"))
G.add_edge((0, "G"), (1, "I"))
G.add_edge((0, "G"), (1, "H"))
G.add_edge((1, "F"), (0, "A"))
G.add_edge((1, "F"), (0, "C"))
G.add_edge((1, "F"), (0, "E"))
G.add_edge((1, "E"), (0, "A"))
G.add_edge((1, "E"), (0, "C"))
G.add_edge((0, "C"), (1, "D"))
G.add_edge((0, "C"), (1, "I"))
G.add_edge((0, "C"), (1, "G"))
G.add_edge((0, "C"), (1, "H"))
G.add_edge((1, "D"), (0, "A"))
G.add_edge((1, "I"), (0, "A"))
G.add_edge((1, "I"), (0, "E"))
G.add_edge((0, "A"), (1, "G"))
G.add_edge((0, "A"), (1, "H"))
G.add_edge((0, "E"), (1, "G"))
G.add_edge((0, "E"), (1, "H"))
self.disconnected_graph = G
def check_match(self, matching):
"""Asserts that the matching is what we expect from the bipartite graph
constructed in the :meth:`setup` fixture.
"""
# For the sake of brevity, rename `matching` to `M`.
M = matching
matched_vertices = frozenset(itertools.chain(*M.items()))
# Assert that the maximum number of vertices (10) is matched.
assert matched_vertices == frozenset(range(12)) - {1, 10}
# Assert that no vertex appears in two edges, or in other words, that
# the matching (u, v) and (v, u) both appear in the matching
# dictionary.
assert all(u == M[M[u]] for u in range(12) if u in M)
def check_vertex_cover(self, vertices):
"""Asserts that the given set of vertices is the vertex cover we
expected from the bipartite graph constructed in the :meth:`setup`
fixture.
"""
# By Konig's theorem, the number of edges in a maximum matching equals
# the number of vertices in a minimum vertex cover.
assert len(vertices) == 5
# Assert that the set is truly a vertex cover.
for (u, v) in self.graph.edges():
assert u in vertices or v in vertices
# TODO Assert that the vertices are the correct ones.
def test_eppstein_matching(self):
"""Tests that David Eppstein's implementation of the Hopcroft--Karp
algorithm produces a maximum cardinality matching.
"""
self.check_match(eppstein_matching(self.graph, self.top_nodes))
def test_hopcroft_karp_matching(self):
"""Tests that the Hopcroft--Karp algorithm produces a maximum
cardinality matching in a bipartite graph.
"""
self.check_match(hopcroft_karp_matching(self.graph, self.top_nodes))
def test_to_vertex_cover(self):
"""Test for converting a maximum matching to a minimum vertex cover."""
matching = maximum_matching(self.graph, self.top_nodes)
vertex_cover = to_vertex_cover(self.graph, matching, self.top_nodes)
self.check_vertex_cover(vertex_cover)
def test_eppstein_matching_simple(self):
match = eppstein_matching(self.simple_graph)
assert match == self.simple_solution
def test_hopcroft_karp_matching_simple(self):
match = hopcroft_karp_matching(self.simple_graph)
assert match == self.simple_solution
def test_eppstein_matching_disconnected(self):
with pytest.raises(nx.AmbiguousSolution):
match = eppstein_matching(self.disconnected_graph)
def test_hopcroft_karp_matching_disconnected(self):
with pytest.raises(nx.AmbiguousSolution):
match = hopcroft_karp_matching(self.disconnected_graph)
def test_issue_2127(self):
"""Test from issue 2127"""
# Build the example DAG
G = nx.DiGraph()
G.add_edge("A", "C")
G.add_edge("A", "B")
G.add_edge("C", "E")
G.add_edge("C", "D")
G.add_edge("E", "G")
G.add_edge("E", "F")
G.add_edge("G", "I")
G.add_edge("G", "H")
tc = nx.transitive_closure(G)
btc = nx.Graph()
# Create a bipartite graph based on the transitive closure of G
for v in tc.nodes():
btc.add_node((0, v))
btc.add_node((1, v))
for u, v in tc.edges():
btc.add_edge((0, u), (1, v))
top_nodes = {n for n in btc if n[0] == 0}
matching = hopcroft_karp_matching(btc, top_nodes)
vertex_cover = to_vertex_cover(btc, matching, top_nodes)
independent_set = set(G) - {v for _, v in vertex_cover}
assert {"B", "D", "F", "I", "H"} == independent_set
def test_vertex_cover_issue_2384(self):
G = nx.Graph([(0, 3), (1, 3), (1, 4), (2, 3)])
matching = maximum_matching(G)
vertex_cover = to_vertex_cover(G, matching)
for u, v in G.edges():
assert u in vertex_cover or v in vertex_cover
def test_unorderable_nodes(self):
a = object()
b = object()
c = object()
d = object()
e = object()
G = nx.Graph([(a, d), (b, d), (b, e), (c, d)])
matching = maximum_matching(G)
vertex_cover = to_vertex_cover(G, matching)
for u, v in G.edges():
assert u in vertex_cover or v in vertex_cover
def test_eppstein_matching():
"""Test in accordance to issue #1927"""
G = nx.Graph()
G.add_nodes_from(["a", 2, 3, 4], bipartite=0)
G.add_nodes_from([1, "b", "c"], bipartite=1)
G.add_edges_from([("a", 1), ("a", "b"), (2, "b"), (2, "c"), (3, "c"), (4, 1)])
matching = eppstein_matching(G)
assert len(matching) == len(maximum_matching(G))
assert all(x in set(matching.keys()) for x in set(matching.values()))
class TestMinimumWeightFullMatching:
@classmethod
def setup_class(cls):
global scipy
scipy = pytest.importorskip("scipy")
def test_minimum_weight_full_matching_incomplete_graph(self):
B = nx.Graph()
B.add_nodes_from([1, 2], bipartite=0)
B.add_nodes_from([3, 4], bipartite=1)
B.add_edge(1, 4, weight=100)
B.add_edge(2, 3, weight=100)
B.add_edge(2, 4, weight=50)
matching = minimum_weight_full_matching(B)
assert matching == {1: 4, 2: 3, 4: 1, 3: 2}
def test_minimum_weight_full_matching_with_no_full_matching(self):
B = nx.Graph()
B.add_nodes_from([1, 2, 3], bipartite=0)
B.add_nodes_from([4, 5, 6], bipartite=1)
B.add_edge(1, 4, weight=100)
B.add_edge(2, 4, weight=100)
B.add_edge(3, 4, weight=50)
B.add_edge(3, 5, weight=50)
B.add_edge(3, 6, weight=50)
with pytest.raises(ValueError):
minimum_weight_full_matching(B)
def test_minimum_weight_full_matching_square(self):
G = nx.complete_bipartite_graph(3, 3)
G.add_edge(0, 3, weight=400)
G.add_edge(0, 4, weight=150)
G.add_edge(0, 5, weight=400)
G.add_edge(1, 3, weight=400)
G.add_edge(1, 4, weight=450)
G.add_edge(1, 5, weight=600)
G.add_edge(2, 3, weight=300)
G.add_edge(2, 4, weight=225)
G.add_edge(2, 5, weight=300)
matching = minimum_weight_full_matching(G)
assert matching == {0: 4, 1: 3, 2: 5, 4: 0, 3: 1, 5: 2}
def test_minimum_weight_full_matching_smaller_left(self):
G = nx.complete_bipartite_graph(3, 4)
G.add_edge(0, 3, weight=400)
G.add_edge(0, 4, weight=150)
G.add_edge(0, 5, weight=400)
G.add_edge(0, 6, weight=1)
G.add_edge(1, 3, weight=400)
G.add_edge(1, 4, weight=450)
G.add_edge(1, 5, weight=600)
G.add_edge(1, 6, weight=2)
G.add_edge(2, 3, weight=300)
G.add_edge(2, 4, weight=225)
G.add_edge(2, 5, weight=290)
G.add_edge(2, 6, weight=3)
matching = minimum_weight_full_matching(G)
assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1}
def test_minimum_weight_full_matching_smaller_top_nodes_right(self):
G = nx.complete_bipartite_graph(3, 4)
G.add_edge(0, 3, weight=400)
G.add_edge(0, 4, weight=150)
G.add_edge(0, 5, weight=400)
G.add_edge(0, 6, weight=1)
G.add_edge(1, 3, weight=400)
G.add_edge(1, 4, weight=450)
G.add_edge(1, 5, weight=600)
G.add_edge(1, 6, weight=2)
G.add_edge(2, 3, weight=300)
G.add_edge(2, 4, weight=225)
G.add_edge(2, 5, weight=290)
G.add_edge(2, 6, weight=3)
matching = minimum_weight_full_matching(G, top_nodes=[3, 4, 5, 6])
assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1}
def test_minimum_weight_full_matching_smaller_right(self):
G = nx.complete_bipartite_graph(4, 3)
G.add_edge(0, 4, weight=400)
G.add_edge(0, 5, weight=400)
G.add_edge(0, 6, weight=300)
G.add_edge(1, 4, weight=150)
G.add_edge(1, 5, weight=450)
G.add_edge(1, 6, weight=225)
G.add_edge(2, 4, weight=400)
G.add_edge(2, 5, weight=600)
G.add_edge(2, 6, weight=290)
G.add_edge(3, 4, weight=1)
G.add_edge(3, 5, weight=2)
G.add_edge(3, 6, weight=3)
matching = minimum_weight_full_matching(G)
assert matching == {1: 4, 2: 6, 3: 5, 4: 1, 5: 3, 6: 2}
def test_minimum_weight_full_matching_negative_weights(self):
G = nx.complete_bipartite_graph(2, 2)
G.add_edge(0, 2, weight=-2)
G.add_edge(0, 3, weight=0.2)
G.add_edge(1, 2, weight=-2)
G.add_edge(1, 3, weight=0.3)
matching = minimum_weight_full_matching(G)
assert matching == {0: 3, 1: 2, 2: 1, 3: 0}
def test_minimum_weight_full_matching_different_weight_key(self):
G = nx.complete_bipartite_graph(2, 2)
G.add_edge(0, 2, mass=2)
G.add_edge(0, 3, mass=0.2)
G.add_edge(1, 2, mass=1)
G.add_edge(1, 3, mass=2)
matching = minimum_weight_full_matching(G, weight="mass")
assert matching == {0: 3, 1: 2, 2: 1, 3: 0}

View file

@ -0,0 +1,79 @@
import pytest
np = pytest.importorskip("numpy")
sp = pytest.importorskip("scipy")
sparse = pytest.importorskip("scipy.sparse")
import networkx as nx
from networkx.algorithms import bipartite
from networkx.testing.utils import assert_edges_equal
class TestBiadjacencyMatrix:
def test_biadjacency_matrix_weight(self):
G = nx.path_graph(5)
G.add_edge(0, 1, weight=2, other=4)
X = [1, 3]
Y = [0, 2, 4]
M = bipartite.biadjacency_matrix(G, X, weight="weight")
assert M[0, 0] == 2
M = bipartite.biadjacency_matrix(G, X, weight="other")
assert M[0, 0] == 4
def test_biadjacency_matrix(self):
tops = [2, 5, 10]
bots = [5, 10, 15]
for i in range(len(tops)):
G = bipartite.random_graph(tops[i], bots[i], 0.2)
top = [n for n, d in G.nodes(data=True) if d["bipartite"] == 0]
M = bipartite.biadjacency_matrix(G, top)
assert M.shape[0] == tops[i]
assert M.shape[1] == bots[i]
def test_biadjacency_matrix_order(self):
G = nx.path_graph(5)
G.add_edge(0, 1, weight=2)
X = [3, 1]
Y = [4, 2, 0]
M = bipartite.biadjacency_matrix(G, X, Y, weight="weight")
assert M[1, 2] == 2
def test_null_graph(self):
with pytest.raises(nx.NetworkXError):
bipartite.biadjacency_matrix(nx.Graph(), [])
def test_empty_graph(self):
with pytest.raises(nx.NetworkXError):
bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [])
def test_duplicate_row(self):
with pytest.raises(nx.NetworkXError):
bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [1, 1])
def test_duplicate_col(self):
with pytest.raises(nx.NetworkXError):
bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], [1, 1])
def test_format_keyword(self):
with pytest.raises(nx.NetworkXError):
bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], format="foo")
def test_from_biadjacency_roundtrip(self):
B1 = nx.path_graph(5)
M = bipartite.biadjacency_matrix(B1, [0, 2, 4])
B2 = bipartite.from_biadjacency_matrix(M)
assert nx.is_isomorphic(B1, B2)
def test_from_biadjacency_weight(self):
M = sparse.csc_matrix([[1, 2], [0, 3]])
B = bipartite.from_biadjacency_matrix(M)
assert_edges_equal(B.edges(), [(0, 2), (0, 3), (1, 3)])
B = bipartite.from_biadjacency_matrix(M, edge_attribute="weight")
e = [(0, 2, {"weight": 1}), (0, 3, {"weight": 2}), (1, 3, {"weight": 3})]
assert_edges_equal(B.edges(data=True), e)
def test_from_biadjacency_multigraph(self):
M = sparse.csc_matrix([[1, 2], [0, 3]])
B = bipartite.from_biadjacency_matrix(M, create_using=nx.MultiGraph())
assert_edges_equal(B.edges(), [(0, 2), (0, 3), (0, 3), (1, 3), (1, 3), (1, 3)])

View file

@ -0,0 +1,392 @@
import networkx as nx
from networkx.algorithms import bipartite
from networkx.testing import assert_edges_equal, assert_nodes_equal
class TestBipartiteProject:
def test_path_projected_graph(self):
G = nx.path_graph(4)
P = bipartite.projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
P = bipartite.projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
def test_path_projected_properties_graph(self):
G = nx.path_graph(4)
G.add_node(1, name="one")
G.add_node(2, name="two")
P = bipartite.projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
assert P.nodes[1]["name"] == G.nodes[1]["name"]
P = bipartite.projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
assert P.nodes[2]["name"] == G.nodes[2]["name"]
def test_path_collaboration_projected_graph(self):
G = nx.path_graph(4)
P = bipartite.collaboration_weighted_projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
P[1][3]["weight"] = 1
P = bipartite.collaboration_weighted_projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
P[0][2]["weight"] = 1
def test_directed_path_collaboration_projected_graph(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
P = bipartite.collaboration_weighted_projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
P[1][3]["weight"] = 1
P = bipartite.collaboration_weighted_projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
P[0][2]["weight"] = 1
def test_path_weighted_projected_graph(self):
G = nx.path_graph(4)
P = bipartite.weighted_projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
P[1][3]["weight"] = 1
P = bipartite.weighted_projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
P[0][2]["weight"] = 1
def test_path_weighted_projected_directed_graph(self):
G = nx.DiGraph()
nx.add_path(G, range(4))
P = bipartite.weighted_projected_graph(G, [1, 3])
assert_nodes_equal(list(P), [1, 3])
assert_edges_equal(list(P.edges()), [(1, 3)])
P[1][3]["weight"] = 1
P = bipartite.weighted_projected_graph(G, [0, 2])
assert_nodes_equal(list(P), [0, 2])
assert_edges_equal(list(P.edges()), [(0, 2)])
P[0][2]["weight"] = 1
def test_star_projected_graph(self):
G = nx.star_graph(3)
P = bipartite.projected_graph(G, [1, 2, 3])
assert_nodes_equal(list(P), [1, 2, 3])
assert_edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)])
P = bipartite.weighted_projected_graph(G, [1, 2, 3])
assert_nodes_equal(list(P), [1, 2, 3])
assert_edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)])
P = bipartite.projected_graph(G, [0])
assert_nodes_equal(list(P), [0])
assert_edges_equal(list(P.edges()), [])
def test_project_multigraph(self):
G = nx.Graph()
G.add_edge("a", 1)
G.add_edge("b", 1)
G.add_edge("a", 2)
G.add_edge("b", 2)
P = bipartite.projected_graph(G, "ab")
assert_edges_equal(list(P.edges()), [("a", "b")])
P = bipartite.weighted_projected_graph(G, "ab")
assert_edges_equal(list(P.edges()), [("a", "b")])
P = bipartite.projected_graph(G, "ab", multigraph=True)
assert_edges_equal(list(P.edges()), [("a", "b"), ("a", "b")])
def test_project_collaboration(self):
G = nx.Graph()
G.add_edge("a", 1)
G.add_edge("b", 1)
G.add_edge("b", 2)
G.add_edge("c", 2)
G.add_edge("c", 3)
G.add_edge("c", 4)
G.add_edge("b", 4)
P = bipartite.collaboration_weighted_projected_graph(G, "abc")
assert P["a"]["b"]["weight"] == 1
assert P["b"]["c"]["weight"] == 2
def test_directed_projection(self):
G = nx.DiGraph()
G.add_edge("A", 1)
G.add_edge(1, "B")
G.add_edge("A", 2)
G.add_edge("B", 2)
P = bipartite.projected_graph(G, "AB")
assert_edges_equal(list(P.edges()), [("A", "B")])
P = bipartite.weighted_projected_graph(G, "AB")
assert_edges_equal(list(P.edges()), [("A", "B")])
assert P["A"]["B"]["weight"] == 1
P = bipartite.projected_graph(G, "AB", multigraph=True)
assert_edges_equal(list(P.edges()), [("A", "B")])
G = nx.DiGraph()
G.add_edge("A", 1)
G.add_edge(1, "B")
G.add_edge("A", 2)
G.add_edge(2, "B")
P = bipartite.projected_graph(G, "AB")
assert_edges_equal(list(P.edges()), [("A", "B")])
P = bipartite.weighted_projected_graph(G, "AB")
assert_edges_equal(list(P.edges()), [("A", "B")])
assert P["A"]["B"]["weight"] == 2
P = bipartite.projected_graph(G, "AB", multigraph=True)
assert_edges_equal(list(P.edges()), [("A", "B"), ("A", "B")])
class TestBipartiteWeightedProjection:
@classmethod
def setup_class(cls):
# Tore Opsahl's example
# http://toreopsahl.com/2009/05/01/projecting-two-mode-networks-onto-weighted-one-mode-networks/
cls.G = nx.Graph()
cls.G.add_edge("A", 1)
cls.G.add_edge("A", 2)
cls.G.add_edge("B", 1)
cls.G.add_edge("B", 2)
cls.G.add_edge("B", 3)
cls.G.add_edge("B", 4)
cls.G.add_edge("B", 5)
cls.G.add_edge("C", 1)
cls.G.add_edge("D", 3)
cls.G.add_edge("E", 4)
cls.G.add_edge("E", 5)
cls.G.add_edge("E", 6)
cls.G.add_edge("F", 6)
# Graph based on figure 6 from Newman (2001)
cls.N = nx.Graph()
cls.N.add_edge("A", 1)
cls.N.add_edge("A", 2)
cls.N.add_edge("A", 3)
cls.N.add_edge("B", 1)
cls.N.add_edge("B", 2)
cls.N.add_edge("B", 3)
cls.N.add_edge("C", 1)
cls.N.add_edge("D", 1)
cls.N.add_edge("E", 3)
def test_project_weighted_shared(self):
edges = [
("A", "B", 2),
("A", "C", 1),
("B", "C", 1),
("B", "D", 1),
("B", "E", 2),
("E", "F", 1),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.weighted_projected_graph(self.G, "ABCDEF")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
edges = [
("A", "B", 3),
("A", "E", 1),
("A", "C", 1),
("A", "D", 1),
("B", "E", 1),
("B", "C", 1),
("B", "D", 1),
("C", "D", 1),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.weighted_projected_graph(self.N, "ABCDE")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
def test_project_weighted_newman(self):
edges = [
("A", "B", 1.5),
("A", "C", 0.5),
("B", "C", 0.5),
("B", "D", 1),
("B", "E", 2),
("E", "F", 1),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.collaboration_weighted_projected_graph(self.G, "ABCDEF")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
edges = [
("A", "B", 11 / 6.0),
("A", "E", 1 / 2.0),
("A", "C", 1 / 3.0),
("A", "D", 1 / 3.0),
("B", "E", 1 / 2.0),
("B", "C", 1 / 3.0),
("B", "D", 1 / 3.0),
("C", "D", 1 / 3.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.collaboration_weighted_projected_graph(self.N, "ABCDE")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
def test_project_weighted_ratio(self):
edges = [
("A", "B", 2 / 6.0),
("A", "C", 1 / 6.0),
("B", "C", 1 / 6.0),
("B", "D", 1 / 6.0),
("B", "E", 2 / 6.0),
("E", "F", 1 / 6.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.weighted_projected_graph(self.G, "ABCDEF", ratio=True)
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
edges = [
("A", "B", 3 / 3.0),
("A", "E", 1 / 3.0),
("A", "C", 1 / 3.0),
("A", "D", 1 / 3.0),
("B", "E", 1 / 3.0),
("B", "C", 1 / 3.0),
("B", "D", 1 / 3.0),
("C", "D", 1 / 3.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.weighted_projected_graph(self.N, "ABCDE", ratio=True)
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
def test_project_weighted_overlap(self):
edges = [
("A", "B", 2 / 2.0),
("A", "C", 1 / 1.0),
("B", "C", 1 / 1.0),
("B", "D", 1 / 1.0),
("B", "E", 2 / 3.0),
("E", "F", 1 / 1.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.overlap_weighted_projected_graph(self.G, "ABCDEF", jaccard=False)
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
edges = [
("A", "B", 3 / 3.0),
("A", "E", 1 / 1.0),
("A", "C", 1 / 1.0),
("A", "D", 1 / 1.0),
("B", "E", 1 / 1.0),
("B", "C", 1 / 1.0),
("B", "D", 1 / 1.0),
("C", "D", 1 / 1.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.overlap_weighted_projected_graph(self.N, "ABCDE", jaccard=False)
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
def test_project_weighted_jaccard(self):
edges = [
("A", "B", 2 / 5.0),
("A", "C", 1 / 2.0),
("B", "C", 1 / 5.0),
("B", "D", 1 / 5.0),
("B", "E", 2 / 6.0),
("E", "F", 1 / 3.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.overlap_weighted_projected_graph(self.G, "ABCDEF")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in list(P.edges()):
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
edges = [
("A", "B", 3 / 3.0),
("A", "E", 1 / 3.0),
("A", "C", 1 / 3.0),
("A", "D", 1 / 3.0),
("B", "E", 1 / 3.0),
("B", "C", 1 / 3.0),
("B", "D", 1 / 3.0),
("C", "D", 1 / 1.0),
]
Panswer = nx.Graph()
Panswer.add_weighted_edges_from(edges)
P = bipartite.overlap_weighted_projected_graph(self.N, "ABCDE")
assert_edges_equal(list(P.edges()), Panswer.edges())
for u, v in P.edges():
assert P[u][v]["weight"] == Panswer[u][v]["weight"]
def test_generic_weighted_projected_graph_simple(self):
def shared(G, u, v):
return len(set(G[u]) & set(G[v]))
B = nx.path_graph(5)
G = bipartite.generic_weighted_projected_graph(
B, [0, 2, 4], weight_function=shared
)
assert_nodes_equal(list(G), [0, 2, 4])
assert_edges_equal(
list(list(G.edges(data=True))),
[(0, 2, {"weight": 1}), (2, 4, {"weight": 1})],
)
G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4])
assert_nodes_equal(list(G), [0, 2, 4])
assert_edges_equal(
list(list(G.edges(data=True))),
[(0, 2, {"weight": 1}), (2, 4, {"weight": 1})],
)
B = nx.DiGraph()
nx.add_path(B, range(5))
G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4])
assert_nodes_equal(list(G), [0, 2, 4])
assert_edges_equal(
list(G.edges(data=True)), [(0, 2, {"weight": 1}), (2, 4, {"weight": 1})]
)
def test_generic_weighted_projected_graph_custom(self):
def jaccard(G, u, v):
unbrs = set(G[u])
vnbrs = set(G[v])
return float(len(unbrs & vnbrs)) / len(unbrs | vnbrs)
def my_weight(G, u, v, weight="weight"):
w = 0
for nbr in set(G[u]) & set(G[v]):
w += G.edges[u, nbr].get(weight, 1) + G.edges[v, nbr].get(weight, 1)
return w
B = nx.bipartite.complete_bipartite_graph(2, 2)
for i, (u, v) in enumerate(B.edges()):
B.edges[u, v]["weight"] = i + 1
G = bipartite.generic_weighted_projected_graph(
B, [0, 1], weight_function=jaccard
)
assert_edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 1.0})])
G = bipartite.generic_weighted_projected_graph(
B, [0, 1], weight_function=my_weight
)
assert_edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 10})])
G = bipartite.generic_weighted_projected_graph(B, [0, 1])
assert_edges_equal(list(G.edges(data=True)), [(0, 1, {"weight": 2})])

View file

@ -0,0 +1,33 @@
"""Unit tests for the :mod:`networkx.algorithms.bipartite.redundancy` module.
"""
import pytest
from networkx import cycle_graph
from networkx import NetworkXError
from networkx.algorithms.bipartite import complete_bipartite_graph
from networkx.algorithms.bipartite import node_redundancy
def test_no_redundant_nodes():
G = complete_bipartite_graph(2, 2)
rc = node_redundancy(G)
assert all(redundancy == 1 for redundancy in rc.values())
def test_redundant_nodes():
G = cycle_graph(6)
edge = {0, 3}
G.add_edge(*edge)
redundancy = node_redundancy(G)
for v in edge:
assert redundancy[v] == 2 / 3
for v in set(G) - edge:
assert redundancy[v] == 1
def test_not_enough_neighbors():
with pytest.raises(NetworkXError):
G = complete_bipartite_graph(1, 2)
node_redundancy(G)

View file

@ -0,0 +1,85 @@
import pytest
import networkx as nx
from networkx.algorithms.bipartite import spectral_bipartivity as sb
from networkx.testing import almost_equal
# Examples from Figure 1
# E. Estrada and J. A. Rodríguez-Velázquez, "Spectral measures of
# bipartivity in complex networks", PhysRev E 72, 046105 (2005)
class TestSpectralBipartivity:
@classmethod
def setup_class(cls):
global scipy
scipy = pytest.importorskip("scipy")
def test_star_like(self):
# star-like
G = nx.star_graph(2)
G.add_edge(1, 2)
assert almost_equal(sb(G), 0.843, places=3)
G = nx.star_graph(3)
G.add_edge(1, 2)
assert almost_equal(sb(G), 0.871, places=3)
G = nx.star_graph(4)
G.add_edge(1, 2)
assert almost_equal(sb(G), 0.890, places=3)
def test_k23_like(self):
# K2,3-like
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(0, 1)
assert almost_equal(sb(G), 0.769, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
assert almost_equal(sb(G), 0.829, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
G.add_edge(3, 4)
assert almost_equal(sb(G), 0.731, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(0, 1)
G.add_edge(2, 4)
assert almost_equal(sb(G), 0.692, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
G.add_edge(3, 4)
G.add_edge(0, 1)
assert almost_equal(sb(G), 0.645, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
G.add_edge(3, 4)
G.add_edge(2, 3)
assert almost_equal(sb(G), 0.645, places=3)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
G.add_edge(3, 4)
G.add_edge(2, 3)
G.add_edge(0, 1)
assert almost_equal(sb(G), 0.597, places=3)
def test_single_nodes(self):
# single nodes
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(2, 4)
sbn = sb(G, nodes=[1, 2])
assert almost_equal(sbn[1], 0.85, places=2)
assert almost_equal(sbn[2], 0.77, places=2)
G = nx.complete_bipartite_graph(2, 3)
G.add_edge(0, 1)
sbn = sb(G, nodes=[1, 2])
assert almost_equal(sbn[1], 0.73, places=2)
assert almost_equal(sbn[2], 0.82, places=2)