up follow livre
This commit is contained in:
parent
70a5c3465c
commit
cffb31c1ef
12198 changed files with 2562132 additions and 35 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,250 @@
|
|||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.algorithms import approximation as approx
|
||||
from networkx.algorithms import threshold
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
progress = 0
|
||||
|
||||
# store the random numbers after setting a global seed
|
||||
np.random.seed(42)
|
||||
np_rv = np.random.rand()
|
||||
random.seed(42)
|
||||
py_rv = random.random()
|
||||
|
||||
|
||||
def t(f, *args, **kwds):
|
||||
"""call one function and check if global RNG changed"""
|
||||
global progress
|
||||
progress += 1
|
||||
print(progress, ",", end="")
|
||||
|
||||
f(*args, **kwds)
|
||||
|
||||
after_np_rv = np.random.rand()
|
||||
# if np_rv != after_np_rv:
|
||||
# print(np_rv, after_np_rv, "don't match np!")
|
||||
assert np_rv == after_np_rv
|
||||
np.random.seed(42)
|
||||
|
||||
after_py_rv = random.random()
|
||||
# if py_rv != after_py_rv:
|
||||
# print(py_rv, after_py_rv, "don't match py!")
|
||||
assert py_rv == after_py_rv
|
||||
random.seed(42)
|
||||
|
||||
|
||||
def run_all_random_functions(seed):
|
||||
n = 20
|
||||
m = 10
|
||||
k = l = 2
|
||||
s = v = 10
|
||||
p = q = p1 = p2 = p_in = p_out = 0.4
|
||||
alpha = radius = theta = 0.75
|
||||
sizes = (20, 20, 10)
|
||||
colors = [1, 2, 3]
|
||||
G = nx.barbell_graph(12, 20)
|
||||
H = nx.cycle_graph(3)
|
||||
H.add_weighted_edges_from((u, v, 0.2) for u, v in H.edges)
|
||||
deg_sequence = [3, 2, 1, 3, 2, 1, 3, 2, 1, 2, 1, 2, 1]
|
||||
in_degree_sequence = w = sequence = aseq = bseq = deg_sequence
|
||||
|
||||
# print("starting...")
|
||||
t(nx.maximal_independent_set, G, seed=seed)
|
||||
t(nx.rich_club_coefficient, G, seed=seed, normalized=False)
|
||||
t(nx.random_reference, G, seed=seed)
|
||||
t(nx.lattice_reference, G, seed=seed)
|
||||
t(nx.sigma, G, 1, 2, seed=seed)
|
||||
t(nx.omega, G, 1, 2, seed=seed)
|
||||
# print("out of smallworld.py")
|
||||
t(nx.double_edge_swap, G, seed=seed)
|
||||
# print("starting connected_double_edge_swap")
|
||||
t(nx.connected_double_edge_swap, nx.complete_graph(9), seed=seed)
|
||||
# print("ending connected_double_edge_swap")
|
||||
t(nx.random_layout, G, seed=seed)
|
||||
t(nx.fruchterman_reingold_layout, G, seed=seed)
|
||||
t(nx.algebraic_connectivity, G, seed=seed)
|
||||
t(nx.fiedler_vector, G, seed=seed)
|
||||
t(nx.spectral_ordering, G, seed=seed)
|
||||
# print('starting average_clustering')
|
||||
t(approx.average_clustering, G, seed=seed)
|
||||
t(approx.simulated_annealing_tsp, H, "greedy", source=1, seed=seed)
|
||||
t(approx.threshold_accepting_tsp, H, "greedy", source=1, seed=seed)
|
||||
t(
|
||||
approx.traveling_salesman_problem,
|
||||
H,
|
||||
method=lambda G, weight: approx.simulated_annealing_tsp(
|
||||
G, "greedy", weight, seed=seed
|
||||
),
|
||||
)
|
||||
t(
|
||||
approx.traveling_salesman_problem,
|
||||
H,
|
||||
method=lambda G, weight: approx.threshold_accepting_tsp(
|
||||
G, "greedy", weight, seed=seed
|
||||
),
|
||||
)
|
||||
t(nx.betweenness_centrality, G, seed=seed)
|
||||
t(nx.edge_betweenness_centrality, G, seed=seed)
|
||||
t(nx.approximate_current_flow_betweenness_centrality, G, seed=seed)
|
||||
# print("kernighan")
|
||||
t(nx.algorithms.community.kernighan_lin_bisection, G, seed=seed)
|
||||
# nx.algorithms.community.asyn_lpa_communities(G, seed=seed)
|
||||
t(nx.algorithms.tree.greedy_branching, G, seed=seed)
|
||||
# print('done with graph argument functions')
|
||||
|
||||
t(nx.spectral_graph_forge, G, alpha, seed=seed)
|
||||
t(nx.algorithms.community.asyn_fluidc, G, k, max_iter=1, seed=seed)
|
||||
t(
|
||||
nx.algorithms.connectivity.edge_augmentation.greedy_k_edge_augmentation,
|
||||
G,
|
||||
k,
|
||||
seed=seed,
|
||||
)
|
||||
t(nx.algorithms.coloring.strategy_random_sequential, G, colors, seed=seed)
|
||||
|
||||
cs = ["d", "i", "i", "d", "d", "i"]
|
||||
t(threshold.swap_d, cs, seed=seed)
|
||||
t(nx.configuration_model, deg_sequence, seed=seed)
|
||||
t(
|
||||
nx.directed_configuration_model,
|
||||
in_degree_sequence,
|
||||
in_degree_sequence,
|
||||
seed=seed,
|
||||
)
|
||||
t(nx.expected_degree_graph, w, seed=seed)
|
||||
t(nx.random_degree_sequence_graph, sequence, seed=seed)
|
||||
joint_degrees = {
|
||||
1: {4: 1},
|
||||
2: {2: 2, 3: 2, 4: 2},
|
||||
3: {2: 2, 4: 1},
|
||||
4: {1: 1, 2: 2, 3: 1},
|
||||
}
|
||||
t(nx.joint_degree_graph, joint_degrees, seed=seed)
|
||||
joint_degree_sequence = [
|
||||
(1, 0),
|
||||
(1, 0),
|
||||
(1, 0),
|
||||
(2, 0),
|
||||
(1, 0),
|
||||
(2, 1),
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
]
|
||||
t(nx.random_clustered_graph, joint_degree_sequence, seed=seed)
|
||||
constructor = [(3, 3, 0.5), (10, 10, 0.7)]
|
||||
t(nx.random_shell_graph, constructor, seed=seed)
|
||||
mapping = {1: 0.4, 2: 0.3, 3: 0.3}
|
||||
t(nx.utils.random_weighted_sample, mapping, k, seed=seed)
|
||||
t(nx.utils.weighted_choice, mapping, seed=seed)
|
||||
t(nx.algorithms.bipartite.configuration_model, aseq, bseq, seed=seed)
|
||||
t(nx.algorithms.bipartite.preferential_attachment_graph, aseq, p, seed=seed)
|
||||
|
||||
def kernel_integral(u, w, z):
|
||||
return z - w
|
||||
|
||||
t(nx.random_kernel_graph, n, kernel_integral, seed=seed)
|
||||
|
||||
sizes = [75, 75, 300]
|
||||
probs = [[0.25, 0.05, 0.02], [0.05, 0.35, 0.07], [0.02, 0.07, 0.40]]
|
||||
t(nx.stochastic_block_model, sizes, probs, seed=seed)
|
||||
t(nx.random_partition_graph, sizes, p_in, p_out, seed=seed)
|
||||
|
||||
# print("starting generator functions")
|
||||
t(threshold.random_threshold_sequence, n, p, seed=seed)
|
||||
t(nx.tournament.random_tournament, n, seed=seed)
|
||||
t(nx.relaxed_caveman_graph, l, k, p, seed=seed)
|
||||
t(nx.planted_partition_graph, l, k, p_in, p_out, seed=seed)
|
||||
t(nx.gaussian_random_partition_graph, n, s, v, p_in, p_out, seed=seed)
|
||||
t(nx.gn_graph, n, seed=seed)
|
||||
t(nx.gnr_graph, n, p, seed=seed)
|
||||
t(nx.gnc_graph, n, seed=seed)
|
||||
t(nx.scale_free_graph, n, seed=seed)
|
||||
t(nx.directed.random_uniform_k_out_graph, n, k, seed=seed)
|
||||
t(nx.random_k_out_graph, n, k, alpha, seed=seed)
|
||||
N = 1000
|
||||
t(nx.partial_duplication_graph, N, n, p, q, seed=seed)
|
||||
t(nx.duplication_divergence_graph, n, p, seed=seed)
|
||||
t(nx.random_geometric_graph, n, radius, seed=seed)
|
||||
t(nx.soft_random_geometric_graph, n, radius, seed=seed)
|
||||
t(nx.geographical_threshold_graph, n, theta, seed=seed)
|
||||
t(nx.waxman_graph, n, seed=seed)
|
||||
t(nx.navigable_small_world_graph, n, seed=seed)
|
||||
t(nx.thresholded_random_geometric_graph, n, radius, theta, seed=seed)
|
||||
t(nx.uniform_random_intersection_graph, n, m, p, seed=seed)
|
||||
t(nx.k_random_intersection_graph, n, m, k, seed=seed)
|
||||
|
||||
t(nx.general_random_intersection_graph, n, 2, [0.1, 0.5], seed=seed)
|
||||
t(nx.fast_gnp_random_graph, n, p, seed=seed)
|
||||
t(nx.gnp_random_graph, n, p, seed=seed)
|
||||
t(nx.dense_gnm_random_graph, n, m, seed=seed)
|
||||
t(nx.gnm_random_graph, n, m, seed=seed)
|
||||
t(nx.newman_watts_strogatz_graph, n, k, p, seed=seed)
|
||||
t(nx.watts_strogatz_graph, n, k, p, seed=seed)
|
||||
t(nx.connected_watts_strogatz_graph, n, k, p, seed=seed)
|
||||
t(nx.random_regular_graph, 3, n, seed=seed)
|
||||
t(nx.barabasi_albert_graph, n, m, seed=seed)
|
||||
t(nx.extended_barabasi_albert_graph, n, m, p, q, seed=seed)
|
||||
t(nx.powerlaw_cluster_graph, n, m, p, seed=seed)
|
||||
t(nx.random_lobster, n, p1, p2, seed=seed)
|
||||
t(nx.random_powerlaw_tree, n, seed=seed, tries=5000)
|
||||
t(nx.random_powerlaw_tree_sequence, 10, seed=seed, tries=5000)
|
||||
t(nx.random_labeled_tree, n, seed=seed)
|
||||
t(nx.utils.powerlaw_sequence, n, seed=seed)
|
||||
t(nx.utils.zipf_rv, 2.3, seed=seed)
|
||||
cdist = [0.2, 0.4, 0.5, 0.7, 0.9, 1.0]
|
||||
t(nx.utils.discrete_sequence, n, cdistribution=cdist, seed=seed)
|
||||
t(nx.algorithms.bipartite.random_graph, n, m, p, seed=seed)
|
||||
t(nx.algorithms.bipartite.gnmk_random_graph, n, m, k, seed=seed)
|
||||
LFR = nx.generators.LFR_benchmark_graph
|
||||
t(
|
||||
LFR,
|
||||
25,
|
||||
3,
|
||||
1.5,
|
||||
0.1,
|
||||
average_degree=3,
|
||||
min_community=10,
|
||||
seed=seed,
|
||||
max_community=20,
|
||||
)
|
||||
t(nx.random_internet_as_graph, n, seed=seed)
|
||||
# print("done")
|
||||
|
||||
|
||||
# choose to test an integer seed, or whether a single RNG can be everywhere
|
||||
# np_rng = np.random.RandomState(14)
|
||||
# seed = np_rng
|
||||
# seed = 14
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
# print("NetworkX Version:", nx.__version__)
|
||||
def test_rng_interface():
|
||||
global progress
|
||||
|
||||
# try different kinds of seeds
|
||||
for seed in [14, np.random.RandomState(14)]:
|
||||
np.random.seed(42)
|
||||
random.seed(42)
|
||||
run_all_random_functions(seed)
|
||||
progress = 0
|
||||
|
||||
# check that both global RNGs are unaffected
|
||||
after_np_rv = np.random.rand()
|
||||
# if np_rv != after_np_rv:
|
||||
# print(np_rv, after_np_rv, "don't match np!")
|
||||
assert np_rv == after_np_rv
|
||||
after_py_rv = random.random()
|
||||
# if py_rv != after_py_rv:
|
||||
# print(py_rv, after_py_rv, "don't match py!")
|
||||
assert py_rv == after_py_rv
|
||||
|
||||
|
||||
# print("\nDone testing seed:", seed)
|
||||
|
||||
# test_rng_interface()
|
||||
321
venv/lib/python3.13/site-packages/networkx/tests/test_convert.py
Normal file
321
venv/lib/python3.13/site-packages/networkx/tests/test_convert.py
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.convert import (
|
||||
from_dict_of_dicts,
|
||||
from_dict_of_lists,
|
||||
to_dict_of_dicts,
|
||||
to_dict_of_lists,
|
||||
to_networkx_graph,
|
||||
)
|
||||
from networkx.generators.classic import barbell_graph, cycle_graph
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
|
||||
class TestConvert:
|
||||
def edgelists_equal(self, e1, e2):
|
||||
return sorted(sorted(e) for e in e1) == sorted(sorted(e) for e in e2)
|
||||
|
||||
def test_simple_graphs(self):
|
||||
for dest, source in [
|
||||
(to_dict_of_dicts, from_dict_of_dicts),
|
||||
(to_dict_of_lists, from_dict_of_lists),
|
||||
]:
|
||||
G = barbell_graph(10, 3)
|
||||
G.graph = {}
|
||||
dod = dest(G)
|
||||
|
||||
# Dict of [dicts, lists]
|
||||
GG = source(dod)
|
||||
assert graphs_equal(G, GG)
|
||||
GW = to_networkx_graph(dod)
|
||||
assert graphs_equal(G, GW)
|
||||
GI = nx.Graph(dod)
|
||||
assert graphs_equal(G, GI)
|
||||
|
||||
# With nodelist keyword
|
||||
P4 = nx.path_graph(4)
|
||||
P3 = nx.path_graph(3)
|
||||
P4.graph = {}
|
||||
P3.graph = {}
|
||||
dod = dest(P4, nodelist=[0, 1, 2])
|
||||
Gdod = nx.Graph(dod)
|
||||
assert graphs_equal(Gdod, P3)
|
||||
|
||||
def test_exceptions(self):
|
||||
# NX graph
|
||||
class G:
|
||||
adj = None
|
||||
|
||||
pytest.raises(nx.NetworkXError, to_networkx_graph, G)
|
||||
|
||||
# pygraphviz agraph
|
||||
class G:
|
||||
is_strict = None
|
||||
|
||||
pytest.raises(nx.NetworkXError, to_networkx_graph, G)
|
||||
|
||||
# Dict of [dicts, lists]
|
||||
G = {"a": 0}
|
||||
pytest.raises(TypeError, to_networkx_graph, G)
|
||||
|
||||
# list or generator of edges
|
||||
class G:
|
||||
next = None
|
||||
|
||||
pytest.raises(nx.NetworkXError, to_networkx_graph, G)
|
||||
|
||||
# no match
|
||||
pytest.raises(nx.NetworkXError, to_networkx_graph, "a")
|
||||
|
||||
def test_digraphs(self):
|
||||
for dest, source in [
|
||||
(to_dict_of_dicts, from_dict_of_dicts),
|
||||
(to_dict_of_lists, from_dict_of_lists),
|
||||
]:
|
||||
G = cycle_graph(10)
|
||||
|
||||
# Dict of [dicts, lists]
|
||||
dod = dest(G)
|
||||
GG = source(dod)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GG.edges()))
|
||||
GW = to_networkx_graph(dod)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GW.edges()))
|
||||
GI = nx.Graph(dod)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GI.edges()))
|
||||
|
||||
G = cycle_graph(10, create_using=nx.DiGraph)
|
||||
dod = dest(G)
|
||||
GG = source(dod, create_using=nx.DiGraph)
|
||||
assert sorted(G.nodes()) == sorted(GG.nodes())
|
||||
assert sorted(G.edges()) == sorted(GG.edges())
|
||||
GW = to_networkx_graph(dod, create_using=nx.DiGraph)
|
||||
assert sorted(G.nodes()) == sorted(GW.nodes())
|
||||
assert sorted(G.edges()) == sorted(GW.edges())
|
||||
GI = nx.DiGraph(dod)
|
||||
assert sorted(G.nodes()) == sorted(GI.nodes())
|
||||
assert sorted(G.edges()) == sorted(GI.edges())
|
||||
|
||||
def test_graph(self):
|
||||
g = nx.cycle_graph(10)
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from(g)
|
||||
G.add_weighted_edges_from((u, v, u) for u, v in g.edges())
|
||||
|
||||
# Dict of dicts
|
||||
dod = to_dict_of_dicts(G)
|
||||
GG = from_dict_of_dicts(dod, create_using=nx.Graph)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GG.edges()))
|
||||
GW = to_networkx_graph(dod, create_using=nx.Graph)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GW.edges()))
|
||||
GI = nx.Graph(dod)
|
||||
assert sorted(G.nodes()) == sorted(GI.nodes())
|
||||
assert sorted(G.edges()) == sorted(GI.edges())
|
||||
|
||||
# Dict of lists
|
||||
dol = to_dict_of_lists(G)
|
||||
GG = from_dict_of_lists(dol, create_using=nx.Graph)
|
||||
# dict of lists throws away edge data so set it to none
|
||||
enone = [(u, v, {}) for (u, v, d) in G.edges(data=True)]
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(enone, sorted(GG.edges(data=True)))
|
||||
GW = to_networkx_graph(dol, create_using=nx.Graph)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(enone, sorted(GW.edges(data=True)))
|
||||
GI = nx.Graph(dol)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes()))
|
||||
assert edges_equal(enone, sorted(GI.edges(data=True)))
|
||||
|
||||
def test_with_multiedges_self_loops(self):
|
||||
G = cycle_graph(10)
|
||||
XG = nx.Graph()
|
||||
XG.add_nodes_from(G)
|
||||
XG.add_weighted_edges_from((u, v, u) for u, v in G.edges())
|
||||
XGM = nx.MultiGraph()
|
||||
XGM.add_nodes_from(G)
|
||||
XGM.add_weighted_edges_from((u, v, u) for u, v in G.edges())
|
||||
XGM.add_edge(0, 1, weight=2) # multiedge
|
||||
XGS = nx.Graph()
|
||||
XGS.add_nodes_from(G)
|
||||
XGS.add_weighted_edges_from((u, v, u) for u, v in G.edges())
|
||||
XGS.add_edge(0, 0, weight=100) # self loop
|
||||
|
||||
# Dict of dicts
|
||||
# with self loops, OK
|
||||
dod = to_dict_of_dicts(XGS)
|
||||
GG = from_dict_of_dicts(dod, create_using=nx.Graph)
|
||||
assert nodes_equal(XGS.nodes(), GG.nodes())
|
||||
assert edges_equal(XGS.edges(), GG.edges())
|
||||
GW = to_networkx_graph(dod, create_using=nx.Graph)
|
||||
assert nodes_equal(XGS.nodes(), GW.nodes())
|
||||
assert edges_equal(XGS.edges(), GW.edges())
|
||||
GI = nx.Graph(dod)
|
||||
assert nodes_equal(XGS.nodes(), GI.nodes())
|
||||
assert edges_equal(XGS.edges(), GI.edges())
|
||||
|
||||
# Dict of lists
|
||||
# with self loops, OK
|
||||
dol = to_dict_of_lists(XGS)
|
||||
GG = from_dict_of_lists(dol, create_using=nx.Graph)
|
||||
# dict of lists throws away edge data so set it to none
|
||||
enone = [(u, v, {}) for (u, v, d) in XGS.edges(data=True)]
|
||||
assert nodes_equal(sorted(XGS.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(enone, sorted(GG.edges(data=True)))
|
||||
GW = to_networkx_graph(dol, create_using=nx.Graph)
|
||||
assert nodes_equal(sorted(XGS.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(enone, sorted(GW.edges(data=True)))
|
||||
GI = nx.Graph(dol)
|
||||
assert nodes_equal(sorted(XGS.nodes()), sorted(GI.nodes()))
|
||||
assert edges_equal(enone, sorted(GI.edges(data=True)))
|
||||
|
||||
# Dict of dicts
|
||||
# with multiedges, OK
|
||||
dod = to_dict_of_dicts(XGM)
|
||||
GG = from_dict_of_dicts(dod, create_using=nx.MultiGraph, multigraph_input=True)
|
||||
assert nodes_equal(sorted(XGM.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(sorted(XGM.edges()), sorted(GG.edges()))
|
||||
GW = to_networkx_graph(dod, create_using=nx.MultiGraph, multigraph_input=True)
|
||||
assert nodes_equal(sorted(XGM.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(sorted(XGM.edges()), sorted(GW.edges()))
|
||||
GI = nx.MultiGraph(dod)
|
||||
assert nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes()))
|
||||
assert sorted(XGM.edges()) == sorted(GI.edges())
|
||||
GE = from_dict_of_dicts(dod, create_using=nx.MultiGraph, multigraph_input=False)
|
||||
assert nodes_equal(sorted(XGM.nodes()), sorted(GE.nodes()))
|
||||
assert sorted(XGM.edges()) != sorted(GE.edges())
|
||||
GI = nx.MultiGraph(XGM)
|
||||
assert nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes()))
|
||||
assert edges_equal(sorted(XGM.edges()), sorted(GI.edges()))
|
||||
GM = nx.MultiGraph(G)
|
||||
assert nodes_equal(sorted(GM.nodes()), sorted(G.nodes()))
|
||||
assert edges_equal(sorted(GM.edges()), sorted(G.edges()))
|
||||
|
||||
# Dict of lists
|
||||
# with multiedges, OK, but better write as DiGraph else you'll
|
||||
# get double edges
|
||||
dol = to_dict_of_lists(G)
|
||||
GG = from_dict_of_lists(dol, create_using=nx.MultiGraph)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GG.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GG.edges()))
|
||||
GW = to_networkx_graph(dol, create_using=nx.MultiGraph)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GW.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GW.edges()))
|
||||
GI = nx.MultiGraph(dol)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(GI.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(GI.edges()))
|
||||
|
||||
def test_edgelists(self):
|
||||
P = nx.path_graph(4)
|
||||
e = [(0, 1), (1, 2), (2, 3)]
|
||||
G = nx.Graph(e)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(P.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(P.edges()))
|
||||
assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True)))
|
||||
|
||||
e = [(0, 1, {}), (1, 2, {}), (2, 3, {})]
|
||||
G = nx.Graph(e)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(P.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(P.edges()))
|
||||
assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True)))
|
||||
|
||||
e = ((n, n + 1) for n in range(3))
|
||||
G = nx.Graph(e)
|
||||
assert nodes_equal(sorted(G.nodes()), sorted(P.nodes()))
|
||||
assert edges_equal(sorted(G.edges()), sorted(P.edges()))
|
||||
assert edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True)))
|
||||
|
||||
def test_directed_to_undirected(self):
|
||||
edges1 = [(0, 1), (1, 2), (2, 0)]
|
||||
edges2 = [(0, 1), (1, 2), (0, 2)]
|
||||
assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges1)).edges(), edges1)
|
||||
assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges2)).edges(), edges1)
|
||||
assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges1)).edges(), edges1)
|
||||
assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges2)).edges(), edges1)
|
||||
|
||||
assert self.edgelists_equal(
|
||||
nx.MultiGraph(nx.MultiDiGraph(edges1)).edges(), edges1
|
||||
)
|
||||
assert self.edgelists_equal(
|
||||
nx.MultiGraph(nx.MultiDiGraph(edges2)).edges(), edges1
|
||||
)
|
||||
|
||||
assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges1)).edges(), edges1)
|
||||
assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges2)).edges(), edges1)
|
||||
|
||||
def test_attribute_dict_integrity(self):
|
||||
# we must not replace dict-like graph data structures with dicts
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from("abc")
|
||||
H = to_networkx_graph(G, create_using=nx.Graph)
|
||||
assert list(H.nodes) == list(G.nodes)
|
||||
H = nx.DiGraph(G)
|
||||
assert list(H.nodes) == list(G.nodes)
|
||||
|
||||
def test_to_edgelist(self):
|
||||
G = nx.Graph([(1, 1)])
|
||||
elist = nx.to_edgelist(G, nodelist=list(G))
|
||||
assert edges_equal(G.edges(data=True), elist)
|
||||
|
||||
def test_custom_node_attr_dict_safekeeping(self):
|
||||
class custom_dict(dict):
|
||||
pass
|
||||
|
||||
class Custom(nx.Graph):
|
||||
node_attr_dict_factory = custom_dict
|
||||
|
||||
g = nx.Graph()
|
||||
g.add_node(1, weight=1)
|
||||
|
||||
h = Custom(g)
|
||||
assert isinstance(g._node[1], dict)
|
||||
assert isinstance(h._node[1], custom_dict)
|
||||
|
||||
# this raise exception
|
||||
# h._node.update((n, dd.copy()) for n, dd in g.nodes.items())
|
||||
# assert isinstance(h._node[1], custom_dict)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"edgelist",
|
||||
(
|
||||
# Graph with no edge data
|
||||
[(0, 1), (1, 2)],
|
||||
# Graph with edge data
|
||||
[(0, 1, {"weight": 1.0}), (1, 2, {"weight": 2.0})],
|
||||
),
|
||||
)
|
||||
def test_to_dict_of_dicts_with_edgedata_param(edgelist):
|
||||
G = nx.Graph()
|
||||
G.add_edges_from(edgelist)
|
||||
# Innermost dict value == edge_data when edge_data != None.
|
||||
# In the case when G has edge data, it is overwritten
|
||||
expected = {0: {1: 10}, 1: {0: 10, 2: 10}, 2: {1: 10}}
|
||||
assert nx.to_dict_of_dicts(G, edge_data=10) == expected
|
||||
|
||||
|
||||
def test_to_dict_of_dicts_with_edgedata_and_nodelist():
|
||||
G = nx.path_graph(5)
|
||||
nodelist = [2, 3, 4]
|
||||
expected = {2: {3: 10}, 3: {2: 10, 4: 10}, 4: {3: 10}}
|
||||
assert nx.to_dict_of_dicts(G, nodelist=nodelist, edge_data=10) == expected
|
||||
|
||||
|
||||
def test_to_dict_of_dicts_with_edgedata_multigraph():
|
||||
"""Multi edge data overwritten when edge_data != None"""
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(0, 1, key="a")
|
||||
G.add_edge(0, 1, key="b")
|
||||
# Multi edge data lost when edge_data is not None
|
||||
expected = {0: {1: 10}, 1: {0: 10}}
|
||||
assert nx.to_dict_of_dicts(G, edge_data=10) == expected
|
||||
|
||||
|
||||
def test_to_networkx_graph_non_edgelist():
|
||||
invalid_edgelist = [1, 2, 3]
|
||||
with pytest.raises(nx.NetworkXError, match="Input is not a valid edge list"):
|
||||
nx.to_networkx_graph(invalid_edgelist)
|
||||
|
|
@ -0,0 +1,531 @@
|
|||
import itertools
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import graphs_equal
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
npt = pytest.importorskip("numpy.testing")
|
||||
|
||||
|
||||
class TestConvertNumpyArray:
|
||||
def setup_method(self):
|
||||
self.G1 = nx.barbell_graph(10, 3)
|
||||
self.G2 = nx.cycle_graph(10, create_using=nx.DiGraph)
|
||||
self.G3 = self.create_weighted(nx.Graph())
|
||||
self.G4 = self.create_weighted(nx.DiGraph())
|
||||
|
||||
def create_weighted(self, G):
|
||||
g = nx.cycle_graph(4)
|
||||
G.add_nodes_from(g)
|
||||
G.add_weighted_edges_from((u, v, 10 + u) for u, v in g.edges())
|
||||
return G
|
||||
|
||||
def assert_equal(self, G1, G2):
|
||||
assert sorted(G1.nodes()) == sorted(G2.nodes())
|
||||
assert sorted(G1.edges()) == sorted(G2.edges())
|
||||
|
||||
def identity_conversion(self, G, A, create_using):
|
||||
assert A.sum() > 0
|
||||
GG = nx.from_numpy_array(A, create_using=create_using)
|
||||
self.assert_equal(G, GG)
|
||||
GW = nx.to_networkx_graph(A, create_using=create_using)
|
||||
self.assert_equal(G, GW)
|
||||
GI = nx.empty_graph(0, create_using).__class__(A)
|
||||
self.assert_equal(G, GI)
|
||||
|
||||
def test_shape(self):
|
||||
"Conversion from non-square array."
|
||||
A = np.array([[1, 2, 3], [4, 5, 6]])
|
||||
pytest.raises(nx.NetworkXError, nx.from_numpy_array, A)
|
||||
|
||||
def test_identity_graph_array(self):
|
||||
"Conversion from graph to array to graph."
|
||||
A = nx.to_numpy_array(self.G1)
|
||||
self.identity_conversion(self.G1, A, nx.Graph())
|
||||
|
||||
def test_identity_digraph_array(self):
|
||||
"""Conversion from digraph to array to digraph."""
|
||||
A = nx.to_numpy_array(self.G2)
|
||||
self.identity_conversion(self.G2, A, nx.DiGraph())
|
||||
|
||||
def test_identity_weighted_graph_array(self):
|
||||
"""Conversion from weighted graph to array to weighted graph."""
|
||||
A = nx.to_numpy_array(self.G3)
|
||||
self.identity_conversion(self.G3, A, nx.Graph())
|
||||
|
||||
def test_identity_weighted_digraph_array(self):
|
||||
"""Conversion from weighted digraph to array to weighted digraph."""
|
||||
A = nx.to_numpy_array(self.G4)
|
||||
self.identity_conversion(self.G4, A, nx.DiGraph())
|
||||
|
||||
def test_nodelist(self):
|
||||
"""Conversion from graph to array to graph with nodelist."""
|
||||
P4 = nx.path_graph(4)
|
||||
P3 = nx.path_graph(3)
|
||||
nodelist = list(P3)
|
||||
A = nx.to_numpy_array(P4, nodelist=nodelist)
|
||||
GA = nx.Graph(A)
|
||||
self.assert_equal(GA, P3)
|
||||
|
||||
# Make nodelist ambiguous by containing duplicates.
|
||||
nodelist += [nodelist[0]]
|
||||
pytest.raises(nx.NetworkXError, nx.to_numpy_array, P3, nodelist=nodelist)
|
||||
|
||||
# Make nodelist invalid by including nonexistent nodes
|
||||
nodelist = [-1, 0, 1]
|
||||
with pytest.raises(
|
||||
nx.NetworkXError,
|
||||
match=f"Nodes {nodelist - P3.nodes} in nodelist is not in G",
|
||||
):
|
||||
nx.to_numpy_array(P3, nodelist=nodelist)
|
||||
|
||||
def test_weight_keyword(self):
|
||||
WP4 = nx.Graph()
|
||||
WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3))
|
||||
P4 = nx.path_graph(4)
|
||||
A = nx.to_numpy_array(P4)
|
||||
np.testing.assert_equal(A, nx.to_numpy_array(WP4, weight=None))
|
||||
np.testing.assert_equal(0.5 * A, nx.to_numpy_array(WP4))
|
||||
np.testing.assert_equal(0.3 * A, nx.to_numpy_array(WP4, weight="other"))
|
||||
|
||||
def test_from_numpy_array_type(self):
|
||||
A = np.array([[1]])
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], int)
|
||||
|
||||
A = np.array([[1]]).astype(float)
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], float)
|
||||
|
||||
A = np.array([[1]]).astype(str)
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], str)
|
||||
|
||||
A = np.array([[1]]).astype(bool)
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], bool)
|
||||
|
||||
A = np.array([[1]]).astype(complex)
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], complex)
|
||||
|
||||
A = np.array([[1]]).astype(object)
|
||||
pytest.raises(TypeError, nx.from_numpy_array, A)
|
||||
|
||||
A = np.array([[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]])
|
||||
with pytest.raises(
|
||||
nx.NetworkXError, match=f"Input array must be 2D, not {A.ndim}"
|
||||
):
|
||||
g = nx.from_numpy_array(A)
|
||||
|
||||
def test_from_numpy_array_dtype(self):
|
||||
dt = [("weight", float), ("cost", int)]
|
||||
A = np.array([[(1.0, 2)]], dtype=dt)
|
||||
G = nx.from_numpy_array(A)
|
||||
assert isinstance(G[0][0]["weight"], float)
|
||||
assert isinstance(G[0][0]["cost"], int)
|
||||
assert G[0][0]["cost"] == 2
|
||||
assert G[0][0]["weight"] == 1.0
|
||||
|
||||
def test_from_numpy_array_parallel_edges(self):
|
||||
"""Tests that the :func:`networkx.from_numpy_array` function
|
||||
interprets integer weights as the number of parallel edges when
|
||||
creating a multigraph.
|
||||
|
||||
"""
|
||||
A = np.array([[1, 1], [1, 2]])
|
||||
# First, with a simple graph, each integer entry in the adjacency
|
||||
# matrix is interpreted as the weight of a single edge in the graph.
|
||||
expected = nx.DiGraph()
|
||||
edges = [(0, 0), (0, 1), (1, 0)]
|
||||
expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges])
|
||||
expected.add_edge(1, 1, weight=2)
|
||||
actual = nx.from_numpy_array(A, parallel_edges=True, create_using=nx.DiGraph)
|
||||
assert graphs_equal(actual, expected)
|
||||
actual = nx.from_numpy_array(A, parallel_edges=False, create_using=nx.DiGraph)
|
||||
assert graphs_equal(actual, expected)
|
||||
# Now each integer entry in the adjacency matrix is interpreted as the
|
||||
# number of parallel edges in the graph if the appropriate keyword
|
||||
# argument is specified.
|
||||
edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)]
|
||||
expected = nx.MultiDiGraph()
|
||||
expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges])
|
||||
actual = nx.from_numpy_array(
|
||||
A, parallel_edges=True, create_using=nx.MultiDiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
expected = nx.MultiDiGraph()
|
||||
expected.add_edges_from(set(edges), weight=1)
|
||||
# The sole self-loop (edge 0) on vertex 1 should have weight 2.
|
||||
expected[1][1][0]["weight"] = 2
|
||||
actual = nx.from_numpy_array(
|
||||
A, parallel_edges=False, create_using=nx.MultiDiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt",
|
||||
(
|
||||
None, # default
|
||||
int, # integer dtype
|
||||
np.dtype(
|
||||
[("weight", "f8"), ("color", "i1")]
|
||||
), # Structured dtype with named fields
|
||||
),
|
||||
)
|
||||
def test_from_numpy_array_no_edge_attr(self, dt):
|
||||
A = np.array([[0, 1], [1, 0]], dtype=dt)
|
||||
G = nx.from_numpy_array(A, edge_attr=None)
|
||||
assert "weight" not in G.edges[0, 1]
|
||||
assert len(G.edges[0, 1]) == 0
|
||||
|
||||
def test_from_numpy_array_multiedge_no_edge_attr(self):
|
||||
A = np.array([[0, 2], [2, 0]])
|
||||
G = nx.from_numpy_array(A, create_using=nx.MultiDiGraph, edge_attr=None)
|
||||
assert all("weight" not in e for _, e in G[0][1].items())
|
||||
assert len(G[0][1][0]) == 0
|
||||
|
||||
def test_from_numpy_array_custom_edge_attr(self):
|
||||
A = np.array([[0, 2], [3, 0]])
|
||||
G = nx.from_numpy_array(A, edge_attr="cost")
|
||||
assert "weight" not in G.edges[0, 1]
|
||||
assert G.edges[0, 1]["cost"] == 3
|
||||
|
||||
def test_symmetric(self):
|
||||
"""Tests that a symmetric array has edges added only once to an
|
||||
undirected multigraph when using :func:`networkx.from_numpy_array`.
|
||||
|
||||
"""
|
||||
A = np.array([[0, 1], [1, 0]])
|
||||
G = nx.from_numpy_array(A, create_using=nx.MultiGraph)
|
||||
expected = nx.MultiGraph()
|
||||
expected.add_edge(0, 1, weight=1)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
def test_dtype_int_graph(self):
|
||||
"""Test that setting dtype int actually gives an integer array.
|
||||
|
||||
For more information, see GitHub pull request #1363.
|
||||
|
||||
"""
|
||||
G = nx.complete_graph(3)
|
||||
A = nx.to_numpy_array(G, dtype=int)
|
||||
assert A.dtype == int
|
||||
|
||||
def test_dtype_int_multigraph(self):
|
||||
"""Test that setting dtype int actually gives an integer array.
|
||||
|
||||
For more information, see GitHub pull request #1363.
|
||||
|
||||
"""
|
||||
G = nx.MultiGraph(nx.complete_graph(3))
|
||||
A = nx.to_numpy_array(G, dtype=int)
|
||||
assert A.dtype == int
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def multigraph_test_graph():
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(1, 2, weight=7)
|
||||
G.add_edge(1, 2, weight=70)
|
||||
return G
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("operator", "expected"), ((sum, 77), (min, 7), (max, 70)))
|
||||
def test_numpy_multigraph(multigraph_test_graph, operator, expected):
|
||||
A = nx.to_numpy_array(multigraph_test_graph, multigraph_weight=operator)
|
||||
assert A[1, 0] == expected
|
||||
|
||||
|
||||
def test_to_numpy_array_multigraph_nodelist(multigraph_test_graph):
|
||||
G = multigraph_test_graph
|
||||
G.add_edge(0, 1, weight=3)
|
||||
A = nx.to_numpy_array(G, nodelist=[1, 2])
|
||||
assert A.shape == (2, 2)
|
||||
assert A[1, 0] == 77
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"G, expected",
|
||||
[
|
||||
(nx.Graph(), np.array([[0, 1 + 2j], [1 + 2j, 0]], dtype=complex)),
|
||||
(nx.DiGraph(), np.array([[0, 1 + 2j], [0, 0]], dtype=complex)),
|
||||
],
|
||||
)
|
||||
def test_to_numpy_array_complex_weights(G, expected):
|
||||
G.add_edge(0, 1, weight=1 + 2j)
|
||||
A = nx.to_numpy_array(G, dtype=complex)
|
||||
npt.assert_array_equal(A, expected)
|
||||
|
||||
|
||||
def test_to_numpy_array_arbitrary_weights():
|
||||
G = nx.DiGraph()
|
||||
w = 922337203685477580102 # Out of range for int64
|
||||
G.add_edge(0, 1, weight=922337203685477580102) # val not representable by int64
|
||||
A = nx.to_numpy_array(G, dtype=object)
|
||||
expected = np.array([[0, w], [0, 0]], dtype=object)
|
||||
npt.assert_array_equal(A, expected)
|
||||
|
||||
# Undirected
|
||||
A = nx.to_numpy_array(G.to_undirected(), dtype=object)
|
||||
expected = np.array([[0, w], [w, 0]], dtype=object)
|
||||
npt.assert_array_equal(A, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"func, expected",
|
||||
((min, -1), (max, 10), (sum, 11), (np.mean, 11 / 3), (np.median, 2)),
|
||||
)
|
||||
def test_to_numpy_array_multiweight_reduction(func, expected):
|
||||
"""Test various functions for reducing multiedge weights."""
|
||||
G = nx.MultiDiGraph()
|
||||
weights = [-1, 2, 10.0]
|
||||
for w in weights:
|
||||
G.add_edge(0, 1, weight=w)
|
||||
A = nx.to_numpy_array(G, multigraph_weight=func, dtype=float)
|
||||
assert np.allclose(A, [[0, expected], [0, 0]])
|
||||
|
||||
# Undirected case
|
||||
A = nx.to_numpy_array(G.to_undirected(), multigraph_weight=func, dtype=float)
|
||||
assert np.allclose(A, [[0, expected], [expected, 0]])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("G, expected"),
|
||||
[
|
||||
(nx.Graph(), [[(0, 0), (10, 5)], [(10, 5), (0, 0)]]),
|
||||
(nx.DiGraph(), [[(0, 0), (10, 5)], [(0, 0), (0, 0)]]),
|
||||
],
|
||||
)
|
||||
def test_to_numpy_array_structured_dtype_attrs_from_fields(G, expected):
|
||||
"""When `dtype` is structured (i.e. has names) and `weight` is None, use
|
||||
the named fields of the dtype to look up edge attributes."""
|
||||
G.add_edge(0, 1, weight=10, cost=5.0)
|
||||
dtype = np.dtype([("weight", int), ("cost", int)])
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None)
|
||||
expected = np.asarray(expected, dtype=dtype)
|
||||
npt.assert_array_equal(A, expected)
|
||||
|
||||
|
||||
def test_to_numpy_array_structured_dtype_single_attr_default():
|
||||
G = nx.path_graph(3)
|
||||
dtype = np.dtype([("weight", float)]) # A single named field
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None)
|
||||
expected = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float)
|
||||
npt.assert_array_equal(A["weight"], expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("field_name", "expected_attr_val"),
|
||||
[
|
||||
("weight", 1),
|
||||
("cost", 3),
|
||||
],
|
||||
)
|
||||
def test_to_numpy_array_structured_dtype_single_attr(field_name, expected_attr_val):
|
||||
G = nx.Graph()
|
||||
G.add_edge(0, 1, cost=3)
|
||||
dtype = np.dtype([(field_name, float)])
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None)
|
||||
expected = np.array([[0, expected_attr_val], [expected_attr_val, 0]], dtype=float)
|
||||
npt.assert_array_equal(A[field_name], expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
||||
@pytest.mark.parametrize(
|
||||
"edge",
|
||||
[
|
||||
(0, 1), # No edge attributes
|
||||
(0, 1, {"weight": 10}), # One edge attr
|
||||
(0, 1, {"weight": 5, "flow": -4}), # Multiple but not all edge attrs
|
||||
(0, 1, {"weight": 2.0, "cost": 10, "flow": -45}), # All attrs
|
||||
],
|
||||
)
|
||||
def test_to_numpy_array_structured_dtype_multiple_fields(graph_type, edge):
|
||||
G = graph_type([edge])
|
||||
dtype = np.dtype([("weight", float), ("cost", float), ("flow", float)])
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None)
|
||||
for attr in dtype.names:
|
||||
expected = nx.to_numpy_array(G, dtype=float, weight=attr)
|
||||
npt.assert_array_equal(A[attr], expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
|
||||
def test_to_numpy_array_structured_dtype_scalar_nonedge(G):
|
||||
G.add_edge(0, 1, weight=10)
|
||||
dtype = np.dtype([("weight", float), ("cost", float)])
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None, nonedge=np.nan)
|
||||
for attr in dtype.names:
|
||||
expected = nx.to_numpy_array(G, dtype=float, weight=attr, nonedge=np.nan)
|
||||
npt.assert_array_equal(A[attr], expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
|
||||
def test_to_numpy_array_structured_dtype_nonedge_ary(G):
|
||||
"""Similar to the scalar case, except has a different non-edge value for
|
||||
each named field."""
|
||||
G.add_edge(0, 1, weight=10)
|
||||
dtype = np.dtype([("weight", float), ("cost", float)])
|
||||
nonedges = np.array([(0, np.inf)], dtype=dtype)
|
||||
A = nx.to_numpy_array(G, dtype=dtype, weight=None, nonedge=nonedges)
|
||||
for attr in dtype.names:
|
||||
nonedge = nonedges[attr]
|
||||
expected = nx.to_numpy_array(G, dtype=float, weight=attr, nonedge=nonedge)
|
||||
npt.assert_array_equal(A[attr], expected)
|
||||
|
||||
|
||||
def test_to_numpy_array_structured_dtype_with_weight_raises():
|
||||
"""Using both a structured dtype (with named fields) and specifying a `weight`
|
||||
parameter is ambiguous."""
|
||||
G = nx.path_graph(3)
|
||||
dtype = np.dtype([("weight", int), ("cost", int)])
|
||||
exception_msg = "Specifying `weight` not supported for structured dtypes"
|
||||
with pytest.raises(ValueError, match=exception_msg):
|
||||
nx.to_numpy_array(G, dtype=dtype) # Default is weight="weight"
|
||||
with pytest.raises(ValueError, match=exception_msg):
|
||||
nx.to_numpy_array(G, dtype=dtype, weight="cost")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
|
||||
def test_to_numpy_array_structured_multigraph_raises(graph_type):
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
dtype = np.dtype([("weight", int), ("cost", int)])
|
||||
with pytest.raises(nx.NetworkXError, match="Structured arrays are not supported"):
|
||||
nx.to_numpy_array(G, dtype=dtype, weight=None)
|
||||
|
||||
|
||||
def test_from_numpy_array_nodelist_bad_size():
|
||||
"""An exception is raised when `len(nodelist) != A.shape[0]`."""
|
||||
n = 5 # Number of nodes
|
||||
A = np.diag(np.ones(n - 1), k=1) # Adj. matrix for P_n
|
||||
expected = nx.path_graph(n)
|
||||
|
||||
assert graphs_equal(nx.from_numpy_array(A, edge_attr=None), expected)
|
||||
nodes = list(range(n))
|
||||
assert graphs_equal(
|
||||
nx.from_numpy_array(A, edge_attr=None, nodelist=nodes), expected
|
||||
)
|
||||
|
||||
# Too many node labels
|
||||
nodes = list(range(n + 1))
|
||||
with pytest.raises(ValueError, match="nodelist must have the same length as A"):
|
||||
nx.from_numpy_array(A, nodelist=nodes)
|
||||
|
||||
# Too few node labels
|
||||
nodes = list(range(n - 1))
|
||||
with pytest.raises(ValueError, match="nodelist must have the same length as A"):
|
||||
nx.from_numpy_array(A, nodelist=nodes)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"nodes",
|
||||
(
|
||||
[4, 3, 2, 1, 0],
|
||||
[9, 7, 1, 2, 8],
|
||||
["a", "b", "c", "d", "e"],
|
||||
[(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)],
|
||||
["A", 2, 7, "spam", (1, 3)],
|
||||
),
|
||||
)
|
||||
def test_from_numpy_array_nodelist(nodes):
|
||||
A = np.diag(np.ones(4), k=1)
|
||||
# Without edge attributes
|
||||
expected = nx.relabel_nodes(
|
||||
nx.path_graph(5), mapping=dict(enumerate(nodes)), copy=True
|
||||
)
|
||||
G = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
# With edge attributes
|
||||
nx.set_edge_attributes(expected, 1.0, name="weight")
|
||||
G = nx.from_numpy_array(A, nodelist=nodes)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"nodes",
|
||||
(
|
||||
[4, 3, 2, 1, 0],
|
||||
[9, 7, 1, 2, 8],
|
||||
["a", "b", "c", "d", "e"],
|
||||
[(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)],
|
||||
["A", 2, 7, "spam", (1, 3)],
|
||||
),
|
||||
)
|
||||
def test_from_numpy_array_nodelist_directed(nodes):
|
||||
A = np.diag(np.ones(4), k=1)
|
||||
# Without edge attributes
|
||||
H = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 4)])
|
||||
expected = nx.relabel_nodes(H, mapping=dict(enumerate(nodes)), copy=True)
|
||||
G = nx.from_numpy_array(A, create_using=nx.DiGraph, edge_attr=None, nodelist=nodes)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
# With edge attributes
|
||||
nx.set_edge_attributes(expected, 1.0, name="weight")
|
||||
G = nx.from_numpy_array(A, create_using=nx.DiGraph, nodelist=nodes)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"nodes",
|
||||
(
|
||||
[4, 3, 2, 1, 0],
|
||||
[9, 7, 1, 2, 8],
|
||||
["a", "b", "c", "d", "e"],
|
||||
[(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)],
|
||||
["A", 2, 7, "spam", (1, 3)],
|
||||
),
|
||||
)
|
||||
def test_from_numpy_array_nodelist_multigraph(nodes):
|
||||
A = np.array(
|
||||
[
|
||||
[0, 1, 0, 0, 0],
|
||||
[1, 0, 2, 0, 0],
|
||||
[0, 2, 0, 3, 0],
|
||||
[0, 0, 3, 0, 4],
|
||||
[0, 0, 0, 4, 0],
|
||||
]
|
||||
)
|
||||
|
||||
H = nx.MultiGraph()
|
||||
for i, edge in enumerate(((0, 1), (1, 2), (2, 3), (3, 4))):
|
||||
H.add_edges_from(itertools.repeat(edge, i + 1))
|
||||
expected = nx.relabel_nodes(H, mapping=dict(enumerate(nodes)), copy=True)
|
||||
|
||||
G = nx.from_numpy_array(
|
||||
A,
|
||||
parallel_edges=True,
|
||||
create_using=nx.MultiGraph,
|
||||
edge_attr=None,
|
||||
nodelist=nodes,
|
||||
)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"nodes",
|
||||
(
|
||||
[4, 3, 2, 1, 0],
|
||||
[9, 7, 1, 2, 8],
|
||||
["a", "b", "c", "d", "e"],
|
||||
[(0, 0), (1, 1), (2, 3), (0, 2), (3, 1)],
|
||||
["A", 2, 7, "spam", (1, 3)],
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("graph", (nx.complete_graph, nx.cycle_graph, nx.wheel_graph))
|
||||
def test_from_numpy_array_nodelist_rountrip(graph, nodes):
|
||||
G = graph(5)
|
||||
A = nx.to_numpy_array(G)
|
||||
expected = nx.relabel_nodes(G, mapping=dict(enumerate(nodes)), copy=True)
|
||||
H = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes)
|
||||
assert graphs_equal(H, expected)
|
||||
|
||||
# With an isolated node
|
||||
G = graph(4)
|
||||
G.add_node("foo")
|
||||
A = nx.to_numpy_array(G)
|
||||
expected = nx.relabel_nodes(G, mapping=dict(zip(G.nodes, nodes)), copy=True)
|
||||
H = nx.from_numpy_array(A, edge_attr=None, nodelist=nodes)
|
||||
assert graphs_equal(H, expected)
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
pd = pytest.importorskip("pandas")
|
||||
|
||||
|
||||
class TestConvertPandas:
|
||||
def setup_method(self):
|
||||
self.rng = np.random.RandomState(seed=5)
|
||||
ints = self.rng.randint(1, 11, size=(3, 2))
|
||||
a = ["A", "B", "C"]
|
||||
b = ["D", "A", "E"]
|
||||
df = pd.DataFrame(ints, columns=["weight", "cost"])
|
||||
df[0] = a # Column label 0 (int)
|
||||
df["b"] = b # Column label 'b' (str)
|
||||
self.df = df
|
||||
|
||||
mdf = pd.DataFrame([[4, 16, "A", "D"]], columns=["weight", "cost", 0, "b"])
|
||||
self.mdf = pd.concat([df, mdf])
|
||||
|
||||
def test_exceptions(self):
|
||||
G = pd.DataFrame(["a"]) # adj
|
||||
pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G)
|
||||
G = pd.DataFrame(["a", 0.0]) # elist
|
||||
pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G)
|
||||
df = pd.DataFrame([[1, 1], [1, 0]], dtype=int, index=[1, 2], columns=["a", "b"])
|
||||
pytest.raises(nx.NetworkXError, nx.from_pandas_adjacency, df)
|
||||
|
||||
def test_from_edgelist_all_attr(self):
|
||||
Gtrue = nx.Graph(
|
||||
[
|
||||
("E", "C", {"cost": 9, "weight": 10}),
|
||||
("B", "A", {"cost": 1, "weight": 7}),
|
||||
("A", "D", {"cost": 7, "weight": 4}),
|
||||
]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", True)
|
||||
assert graphs_equal(G, Gtrue)
|
||||
# MultiGraph
|
||||
MGtrue = nx.MultiGraph(Gtrue)
|
||||
MGtrue.add_edge("A", "D", cost=16, weight=4)
|
||||
MG = nx.from_pandas_edgelist(self.mdf, 0, "b", True, nx.MultiGraph())
|
||||
assert graphs_equal(MG, MGtrue)
|
||||
|
||||
def test_from_edgelist_multi_attr(self):
|
||||
Gtrue = nx.Graph(
|
||||
[
|
||||
("E", "C", {"cost": 9, "weight": 10}),
|
||||
("B", "A", {"cost": 1, "weight": 7}),
|
||||
("A", "D", {"cost": 7, "weight": 4}),
|
||||
]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", ["weight", "cost"])
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_from_edgelist_multi_attr_incl_target(self):
|
||||
Gtrue = nx.Graph(
|
||||
[
|
||||
("E", "C", {0: "C", "b": "E", "weight": 10}),
|
||||
("B", "A", {0: "B", "b": "A", "weight": 7}),
|
||||
("A", "D", {0: "A", "b": "D", "weight": 4}),
|
||||
]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", [0, "b", "weight"])
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_from_edgelist_multidigraph_and_edge_attr(self):
|
||||
# example from issue #2374
|
||||
edges = [
|
||||
("X1", "X4", {"Co": "zA", "Mi": 0, "St": "X1"}),
|
||||
("X1", "X4", {"Co": "zB", "Mi": 54, "St": "X2"}),
|
||||
("X1", "X4", {"Co": "zB", "Mi": 49, "St": "X3"}),
|
||||
("X1", "X4", {"Co": "zB", "Mi": 44, "St": "X4"}),
|
||||
("Y1", "Y3", {"Co": "zC", "Mi": 0, "St": "Y1"}),
|
||||
("Y1", "Y3", {"Co": "zC", "Mi": 34, "St": "Y2"}),
|
||||
("Y1", "Y3", {"Co": "zC", "Mi": 29, "St": "X2"}),
|
||||
("Y1", "Y3", {"Co": "zC", "Mi": 24, "St": "Y3"}),
|
||||
("Z1", "Z3", {"Co": "zD", "Mi": 0, "St": "Z1"}),
|
||||
("Z1", "Z3", {"Co": "zD", "Mi": 14, "St": "X3"}),
|
||||
]
|
||||
Gtrue = nx.MultiDiGraph(edges)
|
||||
data = {
|
||||
"O": ["X1", "X1", "X1", "X1", "Y1", "Y1", "Y1", "Y1", "Z1", "Z1"],
|
||||
"D": ["X4", "X4", "X4", "X4", "Y3", "Y3", "Y3", "Y3", "Z3", "Z3"],
|
||||
"St": ["X1", "X2", "X3", "X4", "Y1", "Y2", "X2", "Y3", "Z1", "X3"],
|
||||
"Co": ["zA", "zB", "zB", "zB", "zC", "zC", "zC", "zC", "zD", "zD"],
|
||||
"Mi": [0, 54, 49, 44, 0, 34, 29, 24, 0, 14],
|
||||
}
|
||||
df = pd.DataFrame.from_dict(data)
|
||||
G1 = nx.from_pandas_edgelist(
|
||||
df, source="O", target="D", edge_attr=True, create_using=nx.MultiDiGraph
|
||||
)
|
||||
G2 = nx.from_pandas_edgelist(
|
||||
df,
|
||||
source="O",
|
||||
target="D",
|
||||
edge_attr=["St", "Co", "Mi"],
|
||||
create_using=nx.MultiDiGraph,
|
||||
)
|
||||
assert graphs_equal(G1, Gtrue)
|
||||
assert graphs_equal(G2, Gtrue)
|
||||
|
||||
def test_from_edgelist_one_attr(self):
|
||||
Gtrue = nx.Graph(
|
||||
[
|
||||
("E", "C", {"weight": 10}),
|
||||
("B", "A", {"weight": 7}),
|
||||
("A", "D", {"weight": 4}),
|
||||
]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", "weight")
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_from_edgelist_int_attr_name(self):
|
||||
# note: this also tests that edge_attr can be `source`
|
||||
Gtrue = nx.Graph(
|
||||
[("E", "C", {0: "C"}), ("B", "A", {0: "B"}), ("A", "D", {0: "A"})]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", 0)
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_from_edgelist_invalid_attr(self):
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", "misspell"
|
||||
)
|
||||
pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, self.df, 0, "b", 1)
|
||||
# see Issue #3562
|
||||
edgeframe = pd.DataFrame([[0, 1], [1, 2], [2, 0]], columns=["s", "t"])
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", True
|
||||
)
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.from_pandas_edgelist, edgeframe, "s", "t", "weight"
|
||||
)
|
||||
pytest.raises(
|
||||
nx.NetworkXError,
|
||||
nx.from_pandas_edgelist,
|
||||
edgeframe,
|
||||
"s",
|
||||
"t",
|
||||
["weight", "size"],
|
||||
)
|
||||
|
||||
def test_from_edgelist_no_attr(self):
|
||||
Gtrue = nx.Graph([("E", "C", {}), ("B", "A", {}), ("A", "D", {})])
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b")
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_from_edgelist(self):
|
||||
# Pandas DataFrame
|
||||
G = nx.cycle_graph(10)
|
||||
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges))
|
||||
|
||||
edgelist = nx.to_edgelist(G)
|
||||
source = [s for s, t, d in edgelist]
|
||||
target = [t for s, t, d in edgelist]
|
||||
weight = [d["weight"] for s, t, d in edgelist]
|
||||
edges = pd.DataFrame({"source": source, "target": target, "weight": weight})
|
||||
|
||||
GG = nx.from_pandas_edgelist(edges, edge_attr="weight")
|
||||
assert nodes_equal(G.nodes(), GG.nodes())
|
||||
assert edges_equal(G.edges(), GG.edges())
|
||||
GW = nx.to_networkx_graph(edges, create_using=nx.Graph)
|
||||
assert nodes_equal(G.nodes(), GW.nodes())
|
||||
assert edges_equal(G.edges(), GW.edges())
|
||||
|
||||
def test_to_edgelist_default_source_or_target_col_exists(self):
|
||||
G = nx.path_graph(10)
|
||||
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges))
|
||||
nx.set_edge_attributes(G, 0, name="source")
|
||||
pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G)
|
||||
|
||||
# drop source column to test an exception raised for the target column
|
||||
for u, v, d in G.edges(data=True):
|
||||
d.pop("source", None)
|
||||
|
||||
nx.set_edge_attributes(G, 0, name="target")
|
||||
pytest.raises(nx.NetworkXError, nx.to_pandas_edgelist, G)
|
||||
|
||||
def test_to_edgelist_custom_source_or_target_col_exists(self):
|
||||
G = nx.path_graph(10)
|
||||
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges))
|
||||
nx.set_edge_attributes(G, 0, name="source_col_name")
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.to_pandas_edgelist, G, source="source_col_name"
|
||||
)
|
||||
|
||||
# drop source column to test an exception raised for the target column
|
||||
for u, v, d in G.edges(data=True):
|
||||
d.pop("source_col_name", None)
|
||||
|
||||
nx.set_edge_attributes(G, 0, name="target_col_name")
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.to_pandas_edgelist, G, target="target_col_name"
|
||||
)
|
||||
|
||||
def test_to_edgelist_edge_key_col_exists(self):
|
||||
G = nx.path_graph(10, create_using=nx.MultiGraph)
|
||||
G.add_weighted_edges_from((u, v, u) for u, v in list(G.edges()))
|
||||
nx.set_edge_attributes(G, 0, name="edge_key_name")
|
||||
pytest.raises(
|
||||
nx.NetworkXError, nx.to_pandas_edgelist, G, edge_key="edge_key_name"
|
||||
)
|
||||
|
||||
def test_from_adjacency(self):
|
||||
nodelist = [1, 2]
|
||||
dftrue = pd.DataFrame(
|
||||
[[1, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist
|
||||
)
|
||||
G = nx.Graph([(1, 1), (1, 2)])
|
||||
df = nx.to_pandas_adjacency(G, dtype=int)
|
||||
pd.testing.assert_frame_equal(df, dftrue)
|
||||
|
||||
@pytest.mark.parametrize("graph", [nx.Graph, nx.MultiGraph])
|
||||
def test_roundtrip(self, graph):
|
||||
# edgelist
|
||||
Gtrue = graph([(1, 1), (1, 2)])
|
||||
df = nx.to_pandas_edgelist(Gtrue)
|
||||
G = nx.from_pandas_edgelist(df, create_using=graph)
|
||||
assert graphs_equal(Gtrue, G)
|
||||
# adjacency
|
||||
adj = {1: {1: {"weight": 1}, 2: {"weight": 1}}, 2: {1: {"weight": 1}}}
|
||||
Gtrue = graph(adj)
|
||||
df = nx.to_pandas_adjacency(Gtrue, dtype=int)
|
||||
G = nx.from_pandas_adjacency(df, create_using=graph)
|
||||
assert graphs_equal(Gtrue, G)
|
||||
|
||||
def test_from_adjacency_named(self):
|
||||
# example from issue #3105
|
||||
data = {
|
||||
"A": {"A": 0, "B": 0, "C": 0},
|
||||
"B": {"A": 1, "B": 0, "C": 0},
|
||||
"C": {"A": 0, "B": 1, "C": 0},
|
||||
}
|
||||
dftrue = pd.DataFrame(data, dtype=np.intp)
|
||||
df = dftrue[["A", "C", "B"]]
|
||||
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph())
|
||||
df = nx.to_pandas_adjacency(G, dtype=np.intp)
|
||||
pd.testing.assert_frame_equal(df, dftrue)
|
||||
|
||||
@pytest.mark.parametrize("edge_attr", [["attr2", "attr3"], True])
|
||||
def test_edgekey_with_multigraph(self, edge_attr):
|
||||
df = pd.DataFrame(
|
||||
{
|
||||
"source": {"A": "N1", "B": "N2", "C": "N1", "D": "N1"},
|
||||
"target": {"A": "N2", "B": "N3", "C": "N1", "D": "N2"},
|
||||
"attr1": {"A": "F1", "B": "F2", "C": "F3", "D": "F4"},
|
||||
"attr2": {"A": 1, "B": 0, "C": 0, "D": 0},
|
||||
"attr3": {"A": 0, "B": 1, "C": 0, "D": 1},
|
||||
}
|
||||
)
|
||||
Gtrue = nx.MultiGraph(
|
||||
[
|
||||
("N1", "N2", "F1", {"attr2": 1, "attr3": 0}),
|
||||
("N2", "N3", "F2", {"attr2": 0, "attr3": 1}),
|
||||
("N1", "N1", "F3", {"attr2": 0, "attr3": 0}),
|
||||
("N1", "N2", "F4", {"attr2": 0, "attr3": 1}),
|
||||
]
|
||||
)
|
||||
# example from issue #4065
|
||||
G = nx.from_pandas_edgelist(
|
||||
df,
|
||||
source="source",
|
||||
target="target",
|
||||
edge_attr=edge_attr,
|
||||
edge_key="attr1",
|
||||
create_using=nx.MultiGraph(),
|
||||
)
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
df_roundtrip = nx.to_pandas_edgelist(G, edge_key="attr1")
|
||||
df_roundtrip = df_roundtrip.sort_values("attr1")
|
||||
df_roundtrip.index = ["A", "B", "C", "D"]
|
||||
pd.testing.assert_frame_equal(
|
||||
df, df_roundtrip[["source", "target", "attr1", "attr2", "attr3"]]
|
||||
)
|
||||
|
||||
def test_edgekey_with_normal_graph_no_action(self):
|
||||
Gtrue = nx.Graph(
|
||||
[
|
||||
("E", "C", {"cost": 9, "weight": 10}),
|
||||
("B", "A", {"cost": 1, "weight": 7}),
|
||||
("A", "D", {"cost": 7, "weight": 4}),
|
||||
]
|
||||
)
|
||||
G = nx.from_pandas_edgelist(self.df, 0, "b", True, edge_key="weight")
|
||||
assert graphs_equal(G, Gtrue)
|
||||
|
||||
def test_nonexisting_edgekey_raises(self):
|
||||
with pytest.raises(nx.exception.NetworkXError):
|
||||
nx.from_pandas_edgelist(
|
||||
self.df,
|
||||
source="source",
|
||||
target="target",
|
||||
edge_key="Not_real",
|
||||
edge_attr=True,
|
||||
create_using=nx.MultiGraph(),
|
||||
)
|
||||
|
||||
def test_multigraph_with_edgekey_no_edgeattrs(self):
|
||||
Gtrue = nx.MultiGraph()
|
||||
Gtrue.add_edge(0, 1, key=0)
|
||||
Gtrue.add_edge(0, 1, key=3)
|
||||
df = nx.to_pandas_edgelist(Gtrue, edge_key="key")
|
||||
expected = pd.DataFrame({"source": [0, 0], "target": [1, 1], "key": [0, 3]})
|
||||
pd.testing.assert_frame_equal(expected, df)
|
||||
G = nx.from_pandas_edgelist(df, edge_key="key", create_using=nx.MultiGraph)
|
||||
assert graphs_equal(Gtrue, G)
|
||||
|
||||
|
||||
def test_to_pandas_adjacency_with_nodelist():
|
||||
G = nx.complete_graph(5)
|
||||
nodelist = [1, 4]
|
||||
expected = pd.DataFrame(
|
||||
[[0, 1], [1, 0]], dtype=int, index=nodelist, columns=nodelist
|
||||
)
|
||||
pd.testing.assert_frame_equal(
|
||||
expected, nx.to_pandas_adjacency(G, nodelist, dtype=int)
|
||||
)
|
||||
|
||||
|
||||
def test_to_pandas_edgelist_with_nodelist():
|
||||
G = nx.Graph()
|
||||
G.add_edges_from([(0, 1), (1, 2), (1, 3)], weight=2.0)
|
||||
G.add_edge(0, 5, weight=100)
|
||||
df = nx.to_pandas_edgelist(G, nodelist=[1, 2])
|
||||
assert 0 not in df["source"].to_numpy()
|
||||
assert 100 not in df["weight"].to_numpy()
|
||||
|
||||
|
||||
def test_from_pandas_adjacency_with_index_collisions():
|
||||
"""See gh-7407"""
|
||||
df = pd.DataFrame(
|
||||
[
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 0, 0],
|
||||
],
|
||||
index=[1010001, 2, 1, 1010002],
|
||||
columns=[1010001, 2, 1, 1010002],
|
||||
)
|
||||
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph)
|
||||
expected = nx.DiGraph([(1010001, 2), (2, 1), (1, 1010002)])
|
||||
assert nodes_equal(G.nodes, expected.nodes)
|
||||
assert edges_equal(G.edges, expected.edges)
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import graphs_equal
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
sp = pytest.importorskip("scipy")
|
||||
|
||||
|
||||
class TestConvertScipy:
|
||||
def setup_method(self):
|
||||
self.G1 = nx.barbell_graph(10, 3)
|
||||
self.G2 = nx.cycle_graph(10, create_using=nx.DiGraph)
|
||||
|
||||
self.G3 = self.create_weighted(nx.Graph())
|
||||
self.G4 = self.create_weighted(nx.DiGraph())
|
||||
|
||||
def test_exceptions(self):
|
||||
class G:
|
||||
format = None
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G)
|
||||
|
||||
def create_weighted(self, G):
|
||||
g = nx.cycle_graph(4)
|
||||
e = list(g.edges())
|
||||
source = [u for u, v in e]
|
||||
dest = [v for u, v in e]
|
||||
weight = [s + 10 for s in source]
|
||||
ex = zip(source, dest, weight)
|
||||
G.add_weighted_edges_from(ex)
|
||||
return G
|
||||
|
||||
def identity_conversion(self, G, A, create_using):
|
||||
GG = nx.from_scipy_sparse_array(A, create_using=create_using)
|
||||
assert nx.is_isomorphic(G, GG)
|
||||
|
||||
GW = nx.to_networkx_graph(A, create_using=create_using)
|
||||
assert nx.is_isomorphic(G, GW)
|
||||
|
||||
GI = nx.empty_graph(0, create_using).__class__(A)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
ACSR = A.tocsr()
|
||||
GI = nx.empty_graph(0, create_using).__class__(ACSR)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
ACOO = A.tocoo()
|
||||
GI = nx.empty_graph(0, create_using).__class__(ACOO)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
ACSC = A.tocsc()
|
||||
GI = nx.empty_graph(0, create_using).__class__(ACSC)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
AD = A.todense()
|
||||
GI = nx.empty_graph(0, create_using).__class__(AD)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
AA = A.toarray()
|
||||
GI = nx.empty_graph(0, create_using).__class__(AA)
|
||||
assert nx.is_isomorphic(G, GI)
|
||||
|
||||
def test_shape(self):
|
||||
"Conversion from non-square sparse array."
|
||||
A = sp.sparse.lil_array([[1, 2, 3], [4, 5, 6]])
|
||||
pytest.raises(nx.NetworkXError, nx.from_scipy_sparse_array, A)
|
||||
|
||||
def test_identity_graph_matrix(self):
|
||||
"Conversion from graph to sparse matrix to graph."
|
||||
A = nx.to_scipy_sparse_array(self.G1)
|
||||
self.identity_conversion(self.G1, A, nx.Graph())
|
||||
|
||||
def test_identity_digraph_matrix(self):
|
||||
"Conversion from digraph to sparse matrix to digraph."
|
||||
A = nx.to_scipy_sparse_array(self.G2)
|
||||
self.identity_conversion(self.G2, A, nx.DiGraph())
|
||||
|
||||
def test_identity_weighted_graph_matrix(self):
|
||||
"""Conversion from weighted graph to sparse matrix to weighted graph."""
|
||||
A = nx.to_scipy_sparse_array(self.G3)
|
||||
self.identity_conversion(self.G3, A, nx.Graph())
|
||||
|
||||
def test_identity_weighted_digraph_matrix(self):
|
||||
"""Conversion from weighted digraph to sparse matrix to weighted digraph."""
|
||||
A = nx.to_scipy_sparse_array(self.G4)
|
||||
self.identity_conversion(self.G4, A, nx.DiGraph())
|
||||
|
||||
def test_nodelist(self):
|
||||
"""Conversion from graph to sparse matrix to graph with nodelist."""
|
||||
P4 = nx.path_graph(4)
|
||||
P3 = nx.path_graph(3)
|
||||
nodelist = list(P3.nodes())
|
||||
A = nx.to_scipy_sparse_array(P4, nodelist=nodelist)
|
||||
GA = nx.Graph(A)
|
||||
assert nx.is_isomorphic(GA, P3)
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=[])
|
||||
# Test nodelist duplicates.
|
||||
long_nl = nodelist + [0]
|
||||
pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=long_nl)
|
||||
|
||||
# Test nodelist contains non-nodes
|
||||
non_nl = [-1, 0, 1, 2]
|
||||
pytest.raises(nx.NetworkXError, nx.to_scipy_sparse_array, P3, nodelist=non_nl)
|
||||
|
||||
def test_weight_keyword(self):
|
||||
WP4 = nx.Graph()
|
||||
WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3))
|
||||
P4 = nx.path_graph(4)
|
||||
A = nx.to_scipy_sparse_array(P4)
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
0.5 * A.todense(), nx.to_scipy_sparse_array(WP4).todense()
|
||||
)
|
||||
np.testing.assert_equal(
|
||||
0.3 * A.todense(), nx.to_scipy_sparse_array(WP4, weight="other").todense()
|
||||
)
|
||||
|
||||
def test_format_keyword(self):
|
||||
WP4 = nx.Graph()
|
||||
WP4.add_edges_from((n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3))
|
||||
P4 = nx.path_graph(4)
|
||||
A = nx.to_scipy_sparse_array(P4, format="csr")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="csc")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="coo")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="bsr")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="lil")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="dia")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
A = nx.to_scipy_sparse_array(P4, format="dok")
|
||||
np.testing.assert_equal(
|
||||
A.todense(), nx.to_scipy_sparse_array(WP4, weight=None).todense()
|
||||
)
|
||||
|
||||
def test_format_keyword_raise(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
WP4 = nx.Graph()
|
||||
WP4.add_edges_from(
|
||||
(n, n + 1, {"weight": 0.5, "other": 0.3}) for n in range(3)
|
||||
)
|
||||
P4 = nx.path_graph(4)
|
||||
nx.to_scipy_sparse_array(P4, format="any_other")
|
||||
|
||||
def test_null_raise(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nx.to_scipy_sparse_array(nx.Graph())
|
||||
|
||||
def test_empty(self):
|
||||
G = nx.Graph()
|
||||
G.add_node(1)
|
||||
M = nx.to_scipy_sparse_array(G)
|
||||
np.testing.assert_equal(M.toarray(), np.array([[0]]))
|
||||
|
||||
def test_ordering(self):
|
||||
G = nx.DiGraph()
|
||||
G.add_edge(1, 2)
|
||||
G.add_edge(2, 3)
|
||||
G.add_edge(3, 1)
|
||||
M = nx.to_scipy_sparse_array(G, nodelist=[3, 2, 1])
|
||||
np.testing.assert_equal(
|
||||
M.toarray(), np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]])
|
||||
)
|
||||
|
||||
def test_selfloop_graph(self):
|
||||
G = nx.Graph([(1, 1)])
|
||||
M = nx.to_scipy_sparse_array(G)
|
||||
np.testing.assert_equal(M.toarray(), np.array([[1]]))
|
||||
|
||||
G.add_edges_from([(2, 3), (3, 4)])
|
||||
M = nx.to_scipy_sparse_array(G, nodelist=[2, 3, 4])
|
||||
np.testing.assert_equal(
|
||||
M.toarray(), np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]])
|
||||
)
|
||||
|
||||
def test_selfloop_digraph(self):
|
||||
G = nx.DiGraph([(1, 1)])
|
||||
M = nx.to_scipy_sparse_array(G)
|
||||
np.testing.assert_equal(M.toarray(), np.array([[1]]))
|
||||
|
||||
G.add_edges_from([(2, 3), (3, 4)])
|
||||
M = nx.to_scipy_sparse_array(G, nodelist=[2, 3, 4])
|
||||
np.testing.assert_equal(
|
||||
M.toarray(), np.array([[0, 1, 0], [0, 0, 1], [0, 0, 0]])
|
||||
)
|
||||
|
||||
def test_from_scipy_sparse_array_parallel_edges(self):
|
||||
"""Tests that the :func:`networkx.from_scipy_sparse_array` function
|
||||
interprets integer weights as the number of parallel edges when
|
||||
creating a multigraph.
|
||||
|
||||
"""
|
||||
A = sp.sparse.csr_array([[1, 1], [1, 2]])
|
||||
# First, with a simple graph, each integer entry in the adjacency
|
||||
# matrix is interpreted as the weight of a single edge in the graph.
|
||||
expected = nx.DiGraph()
|
||||
edges = [(0, 0), (0, 1), (1, 0)]
|
||||
expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges])
|
||||
expected.add_edge(1, 1, weight=2)
|
||||
actual = nx.from_scipy_sparse_array(
|
||||
A, parallel_edges=True, create_using=nx.DiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
actual = nx.from_scipy_sparse_array(
|
||||
A, parallel_edges=False, create_using=nx.DiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
# Now each integer entry in the adjacency matrix is interpreted as the
|
||||
# number of parallel edges in the graph if the appropriate keyword
|
||||
# argument is specified.
|
||||
edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)]
|
||||
expected = nx.MultiDiGraph()
|
||||
expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges])
|
||||
actual = nx.from_scipy_sparse_array(
|
||||
A, parallel_edges=True, create_using=nx.MultiDiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
expected = nx.MultiDiGraph()
|
||||
expected.add_edges_from(set(edges), weight=1)
|
||||
# The sole self-loop (edge 0) on vertex 1 should have weight 2.
|
||||
expected[1][1][0]["weight"] = 2
|
||||
actual = nx.from_scipy_sparse_array(
|
||||
A, parallel_edges=False, create_using=nx.MultiDiGraph
|
||||
)
|
||||
assert graphs_equal(actual, expected)
|
||||
|
||||
def test_symmetric(self):
|
||||
"""Tests that a symmetric matrix has edges added only once to an
|
||||
undirected multigraph when using
|
||||
:func:`networkx.from_scipy_sparse_array`.
|
||||
|
||||
"""
|
||||
A = sp.sparse.csr_array([[0, 1], [1, 0]])
|
||||
G = nx.from_scipy_sparse_array(A, create_using=nx.MultiGraph)
|
||||
expected = nx.MultiGraph()
|
||||
expected.add_edge(0, 1, weight=1)
|
||||
assert graphs_equal(G, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sparse_format", ("csr", "csc", "dok"))
|
||||
def test_from_scipy_sparse_array_formats(sparse_format):
|
||||
"""Test all formats supported by _generate_weighted_edges."""
|
||||
# trinode complete graph with non-uniform edge weights
|
||||
expected = nx.Graph()
|
||||
expected.add_edges_from(
|
||||
[
|
||||
(0, 1, {"weight": 3}),
|
||||
(0, 2, {"weight": 2}),
|
||||
(1, 0, {"weight": 3}),
|
||||
(1, 2, {"weight": 1}),
|
||||
(2, 0, {"weight": 2}),
|
||||
(2, 1, {"weight": 1}),
|
||||
]
|
||||
)
|
||||
A = sp.sparse.coo_array([[0, 3, 2], [3, 0, 1], [2, 1, 0]]).asformat(sparse_format)
|
||||
assert graphs_equal(expected, nx.from_scipy_sparse_array(A))
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
# smoke tests for exceptions
|
||||
|
||||
|
||||
def test_raises_networkxexception():
|
||||
with pytest.raises(nx.NetworkXException):
|
||||
raise nx.NetworkXException
|
||||
|
||||
|
||||
def test_raises_networkxerr():
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
raise nx.NetworkXError
|
||||
|
||||
|
||||
def test_raises_networkx_pointless_concept():
|
||||
with pytest.raises(nx.NetworkXPointlessConcept):
|
||||
raise nx.NetworkXPointlessConcept
|
||||
|
||||
|
||||
def test_raises_networkxalgorithmerr():
|
||||
with pytest.raises(nx.NetworkXAlgorithmError):
|
||||
raise nx.NetworkXAlgorithmError
|
||||
|
||||
|
||||
def test_raises_networkx_unfeasible():
|
||||
with pytest.raises(nx.NetworkXUnfeasible):
|
||||
raise nx.NetworkXUnfeasible
|
||||
|
||||
|
||||
def test_raises_networkx_no_path():
|
||||
with pytest.raises(nx.NetworkXNoPath):
|
||||
raise nx.NetworkXNoPath
|
||||
|
||||
|
||||
def test_raises_networkx_unbounded():
|
||||
with pytest.raises(nx.NetworkXUnbounded):
|
||||
raise nx.NetworkXUnbounded
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import pytest
|
||||
|
||||
|
||||
def test_namespace_alias():
|
||||
with pytest.raises(ImportError):
|
||||
from networkx import nx
|
||||
|
||||
|
||||
def test_namespace_nesting():
|
||||
with pytest.raises(ImportError):
|
||||
from networkx import networkx
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import sys
|
||||
import types
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx.lazy_imports as lazy
|
||||
|
||||
|
||||
def test_lazy_import_basics():
|
||||
math = lazy._lazy_import("math")
|
||||
anything_not_real = lazy._lazy_import("anything_not_real")
|
||||
|
||||
# Now test that accessing attributes does what it should
|
||||
assert math.sin(math.pi) == pytest.approx(0, 1e-6)
|
||||
# poor-mans pytest.raises for testing errors on attribute access
|
||||
try:
|
||||
anything_not_real.pi
|
||||
assert False # Should not get here
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
assert isinstance(anything_not_real, lazy.DelayedImportErrorModule)
|
||||
# see if it changes for second access
|
||||
try:
|
||||
anything_not_real.pi
|
||||
assert False # Should not get here
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def test_lazy_import_impact_on_sys_modules():
|
||||
math = lazy._lazy_import("math")
|
||||
anything_not_real = lazy._lazy_import("anything_not_real")
|
||||
|
||||
assert isinstance(math, types.ModuleType)
|
||||
assert "math" in sys.modules
|
||||
assert type(anything_not_real) is lazy.DelayedImportErrorModule
|
||||
assert "anything_not_real" not in sys.modules
|
||||
|
||||
# only do this if numpy is installed
|
||||
np_test = pytest.importorskip("numpy")
|
||||
np = lazy._lazy_import("numpy")
|
||||
assert isinstance(np, types.ModuleType)
|
||||
assert "numpy" in sys.modules
|
||||
|
||||
np.pi # trigger load of numpy
|
||||
|
||||
assert isinstance(np, types.ModuleType)
|
||||
assert "numpy" in sys.modules
|
||||
|
||||
|
||||
def test_lazy_import_nonbuiltins():
|
||||
sp = lazy._lazy_import("scipy")
|
||||
np = lazy._lazy_import("numpy")
|
||||
if isinstance(sp, lazy.DelayedImportErrorModule):
|
||||
try:
|
||||
sp.special.erf
|
||||
assert False
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
elif isinstance(np, lazy.DelayedImportErrorModule):
|
||||
try:
|
||||
np.sin(np.pi)
|
||||
assert False
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
else:
|
||||
assert sp.special.erf(np.pi) == pytest.approx(1, 1e-4)
|
||||
|
||||
|
||||
def test_lazy_attach():
|
||||
name = "mymod"
|
||||
submods = ["mysubmodule", "anothersubmodule"]
|
||||
myall = {"not_real_submod": ["some_var_or_func"]}
|
||||
|
||||
locls = {
|
||||
"attach": lazy.attach,
|
||||
"name": name,
|
||||
"submods": submods,
|
||||
"myall": myall,
|
||||
}
|
||||
s = "__getattr__, __lazy_dir__, __all__ = attach(name, submods, myall)"
|
||||
|
||||
exec(s, {}, locls)
|
||||
expected = {
|
||||
"attach": lazy.attach,
|
||||
"name": name,
|
||||
"submods": submods,
|
||||
"myall": myall,
|
||||
"__getattr__": None,
|
||||
"__lazy_dir__": None,
|
||||
"__all__": None,
|
||||
}
|
||||
assert locls.keys() == expected.keys()
|
||||
for k, v in expected.items():
|
||||
if v is not None:
|
||||
assert locls[k] == v
|
||||
347
venv/lib/python3.13/site-packages/networkx/tests/test_relabel.py
Normal file
347
venv/lib/python3.13/site-packages/networkx/tests/test_relabel.py
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.generators.classic import empty_graph
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestRelabel:
|
||||
def test_convert_node_labels_to_integers(self):
|
||||
# test that empty graph converts fine for all options
|
||||
G = empty_graph()
|
||||
H = nx.convert_node_labels_to_integers(G, 100)
|
||||
assert list(H.nodes()) == []
|
||||
assert list(H.edges()) == []
|
||||
|
||||
for opt in ["default", "sorted", "increasing degree", "decreasing degree"]:
|
||||
G = empty_graph()
|
||||
H = nx.convert_node_labels_to_integers(G, 100, ordering=opt)
|
||||
assert list(H.nodes()) == []
|
||||
assert list(H.edges()) == []
|
||||
|
||||
G = empty_graph()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
H = nx.convert_node_labels_to_integers(G)
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
|
||||
H = nx.convert_node_labels_to_integers(G, 1000)
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
assert nodes_equal(H.nodes(), [1000, 1001, 1002, 1003])
|
||||
|
||||
H = nx.convert_node_labels_to_integers(G, ordering="increasing degree")
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
assert H.degree(0) == 1
|
||||
assert H.degree(1) == 2
|
||||
assert H.degree(2) == 2
|
||||
assert H.degree(3) == 3
|
||||
|
||||
H = nx.convert_node_labels_to_integers(G, ordering="decreasing degree")
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
assert H.degree(0) == 3
|
||||
assert H.degree(1) == 2
|
||||
assert H.degree(2) == 2
|
||||
assert H.degree(3) == 1
|
||||
|
||||
H = nx.convert_node_labels_to_integers(
|
||||
G, ordering="increasing degree", label_attribute="label"
|
||||
)
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
assert H.degree(0) == 1
|
||||
assert H.degree(1) == 2
|
||||
assert H.degree(2) == 2
|
||||
assert H.degree(3) == 3
|
||||
|
||||
# check mapping
|
||||
assert H.nodes[3]["label"] == "C"
|
||||
assert H.nodes[0]["label"] == "D"
|
||||
assert H.nodes[1]["label"] == "A" or H.nodes[2]["label"] == "A"
|
||||
assert H.nodes[1]["label"] == "B" or H.nodes[2]["label"] == "B"
|
||||
|
||||
def test_convert_to_integers2(self):
|
||||
G = empty_graph()
|
||||
G.add_edges_from([("C", "D"), ("A", "B"), ("A", "C"), ("B", "C")])
|
||||
H = nx.convert_node_labels_to_integers(G, ordering="sorted")
|
||||
degH = (d for n, d in H.degree())
|
||||
degG = (d for n, d in G.degree())
|
||||
assert sorted(degH) == sorted(degG)
|
||||
|
||||
H = nx.convert_node_labels_to_integers(
|
||||
G, ordering="sorted", label_attribute="label"
|
||||
)
|
||||
assert H.nodes[0]["label"] == "A"
|
||||
assert H.nodes[1]["label"] == "B"
|
||||
assert H.nodes[2]["label"] == "C"
|
||||
assert H.nodes[3]["label"] == "D"
|
||||
|
||||
def test_convert_to_integers_raise(self):
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G = nx.Graph()
|
||||
H = nx.convert_node_labels_to_integers(G, ordering="increasing age")
|
||||
|
||||
def test_relabel_nodes_copy(self):
|
||||
G = nx.empty_graph()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"}
|
||||
H = nx.relabel_nodes(G, mapping)
|
||||
assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"])
|
||||
|
||||
def test_relabel_nodes_function(self):
|
||||
G = nx.empty_graph()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
# function mapping no longer encouraged but works
|
||||
|
||||
def mapping(n):
|
||||
return ord(n)
|
||||
|
||||
H = nx.relabel_nodes(G, mapping)
|
||||
assert nodes_equal(H.nodes(), [65, 66, 67, 68])
|
||||
|
||||
def test_relabel_nodes_callable_type(self):
|
||||
G = nx.path_graph(4)
|
||||
H = nx.relabel_nodes(G, str)
|
||||
assert nodes_equal(H.nodes, ["0", "1", "2", "3"])
|
||||
|
||||
@pytest.mark.parametrize("non_mc", ("0123", ["0", "1", "2", "3"]))
|
||||
def test_relabel_nodes_non_mapping_or_callable(self, non_mc):
|
||||
"""If `mapping` is neither a Callable or a Mapping, an exception
|
||||
should be raised."""
|
||||
G = nx.path_graph(4)
|
||||
with pytest.raises(AttributeError):
|
||||
nx.relabel_nodes(G, non_mc)
|
||||
|
||||
def test_relabel_nodes_graph(self):
|
||||
G = nx.Graph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"}
|
||||
H = nx.relabel_nodes(G, mapping)
|
||||
assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"])
|
||||
|
||||
def test_relabel_nodes_orderedgraph(self):
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from([1, 2, 3])
|
||||
G.add_edges_from([(1, 3), (2, 3)])
|
||||
mapping = {1: "a", 2: "b", 3: "c"}
|
||||
H = nx.relabel_nodes(G, mapping)
|
||||
assert list(H.nodes) == ["a", "b", "c"]
|
||||
|
||||
def test_relabel_nodes_digraph(self):
|
||||
G = nx.DiGraph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
mapping = {"A": "aardvark", "B": "bear", "C": "cat", "D": "dog"}
|
||||
H = nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert nodes_equal(H.nodes(), ["aardvark", "bear", "cat", "dog"])
|
||||
|
||||
def test_relabel_nodes_multigraph(self):
|
||||
G = nx.MultiGraph([("a", "b"), ("a", "b")])
|
||||
mapping = {"a": "aardvark", "b": "bear"}
|
||||
G = nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert nodes_equal(G.nodes(), ["aardvark", "bear"])
|
||||
assert edges_equal(G.edges(), [("aardvark", "bear"), ("aardvark", "bear")])
|
||||
|
||||
def test_relabel_nodes_multidigraph(self):
|
||||
G = nx.MultiDiGraph([("a", "b"), ("a", "b")])
|
||||
mapping = {"a": "aardvark", "b": "bear"}
|
||||
G = nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert nodes_equal(G.nodes(), ["aardvark", "bear"])
|
||||
assert edges_equal(G.edges(), [("aardvark", "bear"), ("aardvark", "bear")])
|
||||
|
||||
def test_relabel_isolated_nodes_to_same(self):
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from(range(4))
|
||||
mapping = {1: 1}
|
||||
H = nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert nodes_equal(H.nodes(), list(range(4)))
|
||||
|
||||
def test_relabel_nodes_missing(self):
|
||||
G = nx.Graph([("A", "B"), ("A", "C"), ("B", "C"), ("C", "D")])
|
||||
mapping = {0: "aardvark"}
|
||||
# copy=True
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
assert nodes_equal(H.nodes, G.nodes)
|
||||
# copy=False
|
||||
GG = G.copy()
|
||||
nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert nodes_equal(G.nodes, GG.nodes)
|
||||
|
||||
def test_relabel_copy_name(self):
|
||||
G = nx.Graph()
|
||||
H = nx.relabel_nodes(G, {}, copy=True)
|
||||
assert H.graph == G.graph
|
||||
H = nx.relabel_nodes(G, {}, copy=False)
|
||||
assert H.graph == G.graph
|
||||
G.name = "first"
|
||||
H = nx.relabel_nodes(G, {}, copy=True)
|
||||
assert H.graph == G.graph
|
||||
H = nx.relabel_nodes(G, {}, copy=False)
|
||||
assert H.graph == G.graph
|
||||
|
||||
def test_relabel_toposort(self):
|
||||
K5 = nx.complete_graph(4)
|
||||
G = nx.complete_graph(4)
|
||||
G = nx.relabel_nodes(G, {i: i + 1 for i in range(4)}, copy=False)
|
||||
assert nx.is_isomorphic(K5, G)
|
||||
G = nx.complete_graph(4)
|
||||
G = nx.relabel_nodes(G, {i: i - 1 for i in range(4)}, copy=False)
|
||||
assert nx.is_isomorphic(K5, G)
|
||||
|
||||
def test_relabel_selfloop(self):
|
||||
G = nx.DiGraph([(1, 1), (1, 2), (2, 3)])
|
||||
G = nx.relabel_nodes(G, {1: "One", 2: "Two", 3: "Three"}, copy=False)
|
||||
assert nodes_equal(G.nodes(), ["One", "Three", "Two"])
|
||||
G = nx.MultiDiGraph([(1, 1), (1, 2), (2, 3)])
|
||||
G = nx.relabel_nodes(G, {1: "One", 2: "Two", 3: "Three"}, copy=False)
|
||||
assert nodes_equal(G.nodes(), ["One", "Three", "Two"])
|
||||
G = nx.MultiDiGraph([(1, 1)])
|
||||
G = nx.relabel_nodes(G, {1: 0}, copy=False)
|
||||
assert nodes_equal(G.nodes(), [0])
|
||||
|
||||
def test_relabel_multidigraph_inout_merge_nodes(self):
|
||||
for MG in (nx.MultiGraph, nx.MultiDiGraph):
|
||||
for cc in (True, False):
|
||||
G = MG([(0, 4), (1, 4), (4, 2), (4, 3)])
|
||||
G[0][4][0]["value"] = "a"
|
||||
G[1][4][0]["value"] = "b"
|
||||
G[4][2][0]["value"] = "c"
|
||||
G[4][3][0]["value"] = "d"
|
||||
G.add_edge(0, 4, key="x", value="e")
|
||||
G.add_edge(4, 3, key="x", value="f")
|
||||
mapping = {0: 9, 1: 9, 2: 9, 3: 9}
|
||||
H = nx.relabel_nodes(G, mapping, copy=cc)
|
||||
# No ordering on keys enforced
|
||||
assert {"value": "a"} in H[9][4].values()
|
||||
assert {"value": "b"} in H[9][4].values()
|
||||
assert {"value": "c"} in H[4][9].values()
|
||||
assert len(H[4][9]) == 3 if G.is_directed() else 6
|
||||
assert {"value": "d"} in H[4][9].values()
|
||||
assert {"value": "e"} in H[9][4].values()
|
||||
assert {"value": "f"} in H[4][9].values()
|
||||
assert len(H[9][4]) == 3 if G.is_directed() else 6
|
||||
|
||||
def test_relabel_multigraph_merge_inplace(self):
|
||||
G = nx.MultiGraph([(0, 1), (0, 2), (0, 3), (0, 1), (0, 2), (0, 3)])
|
||||
G[0][1][0]["value"] = "a"
|
||||
G[0][2][0]["value"] = "b"
|
||||
G[0][3][0]["value"] = "c"
|
||||
mapping = {1: 4, 2: 4, 3: 4}
|
||||
nx.relabel_nodes(G, mapping, copy=False)
|
||||
# No ordering on keys enforced
|
||||
assert {"value": "a"} in G[0][4].values()
|
||||
assert {"value": "b"} in G[0][4].values()
|
||||
assert {"value": "c"} in G[0][4].values()
|
||||
|
||||
def test_relabel_multidigraph_merge_inplace(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 2), (0, 3)])
|
||||
G[0][1][0]["value"] = "a"
|
||||
G[0][2][0]["value"] = "b"
|
||||
G[0][3][0]["value"] = "c"
|
||||
mapping = {1: 4, 2: 4, 3: 4}
|
||||
nx.relabel_nodes(G, mapping, copy=False)
|
||||
# No ordering on keys enforced
|
||||
assert {"value": "a"} in G[0][4].values()
|
||||
assert {"value": "b"} in G[0][4].values()
|
||||
assert {"value": "c"} in G[0][4].values()
|
||||
|
||||
def test_relabel_multidigraph_inout_copy(self):
|
||||
G = nx.MultiDiGraph([(0, 4), (1, 4), (4, 2), (4, 3)])
|
||||
G[0][4][0]["value"] = "a"
|
||||
G[1][4][0]["value"] = "b"
|
||||
G[4][2][0]["value"] = "c"
|
||||
G[4][3][0]["value"] = "d"
|
||||
G.add_edge(0, 4, key="x", value="e")
|
||||
G.add_edge(4, 3, key="x", value="f")
|
||||
mapping = {0: 9, 1: 9, 2: 9, 3: 9}
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
# No ordering on keys enforced
|
||||
assert {"value": "a"} in H[9][4].values()
|
||||
assert {"value": "b"} in H[9][4].values()
|
||||
assert {"value": "c"} in H[4][9].values()
|
||||
assert len(H[4][9]) == 3
|
||||
assert {"value": "d"} in H[4][9].values()
|
||||
assert {"value": "e"} in H[9][4].values()
|
||||
assert {"value": "f"} in H[4][9].values()
|
||||
assert len(H[9][4]) == 3
|
||||
|
||||
def test_relabel_multigraph_merge_copy(self):
|
||||
G = nx.MultiGraph([(0, 1), (0, 2), (0, 3)])
|
||||
G[0][1][0]["value"] = "a"
|
||||
G[0][2][0]["value"] = "b"
|
||||
G[0][3][0]["value"] = "c"
|
||||
mapping = {1: 4, 2: 4, 3: 4}
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
assert {"value": "a"} in H[0][4].values()
|
||||
assert {"value": "b"} in H[0][4].values()
|
||||
assert {"value": "c"} in H[0][4].values()
|
||||
|
||||
def test_relabel_multidigraph_merge_copy(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 2), (0, 3)])
|
||||
G[0][1][0]["value"] = "a"
|
||||
G[0][2][0]["value"] = "b"
|
||||
G[0][3][0]["value"] = "c"
|
||||
mapping = {1: 4, 2: 4, 3: 4}
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
assert {"value": "a"} in H[0][4].values()
|
||||
assert {"value": "b"} in H[0][4].values()
|
||||
assert {"value": "c"} in H[0][4].values()
|
||||
|
||||
def test_relabel_multigraph_nonnumeric_key(self):
|
||||
for MG in (nx.MultiGraph, nx.MultiDiGraph):
|
||||
for cc in (True, False):
|
||||
G = nx.MultiGraph()
|
||||
G.add_edge(0, 1, key="I", value="a")
|
||||
G.add_edge(0, 2, key="II", value="b")
|
||||
G.add_edge(0, 3, key="II", value="c")
|
||||
mapping = {1: 4, 2: 4, 3: 4}
|
||||
nx.relabel_nodes(G, mapping, copy=False)
|
||||
assert {"value": "a"} in G[0][4].values()
|
||||
assert {"value": "b"} in G[0][4].values()
|
||||
assert {"value": "c"} in G[0][4].values()
|
||||
assert 0 in G[0][4]
|
||||
assert "I" in G[0][4]
|
||||
assert "II" in G[0][4]
|
||||
|
||||
def test_relabel_circular(self):
|
||||
G = nx.path_graph(3)
|
||||
mapping = {0: 1, 1: 0}
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
with pytest.raises(nx.NetworkXUnfeasible):
|
||||
H = nx.relabel_nodes(G, mapping, copy=False)
|
||||
|
||||
def test_relabel_preserve_node_order_full_mapping_with_copy_true(self):
|
||||
G = nx.path_graph(3)
|
||||
original_order = list(G.nodes())
|
||||
mapping = {2: "a", 1: "b", 0: "c"} # dictionary keys out of order on purpose
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
new_order = list(H.nodes())
|
||||
assert [mapping.get(i, i) for i in original_order] == new_order
|
||||
|
||||
def test_relabel_preserve_node_order_full_mapping_with_copy_false(self):
|
||||
G = nx.path_graph(3)
|
||||
original_order = list(G)
|
||||
mapping = {2: "a", 1: "b", 0: "c"} # dictionary keys out of order on purpose
|
||||
H = nx.relabel_nodes(G, mapping, copy=False)
|
||||
new_order = list(H)
|
||||
assert [mapping.get(i, i) for i in original_order] == new_order
|
||||
|
||||
def test_relabel_preserve_node_order_partial_mapping_with_copy_true(self):
|
||||
G = nx.path_graph(3)
|
||||
original_order = list(G)
|
||||
mapping = {1: "a", 0: "b"} # partial mapping and keys out of order on purpose
|
||||
H = nx.relabel_nodes(G, mapping, copy=True)
|
||||
new_order = list(H)
|
||||
assert [mapping.get(i, i) for i in original_order] == new_order
|
||||
|
||||
def test_relabel_preserve_node_order_partial_mapping_with_copy_false(self):
|
||||
G = nx.path_graph(3)
|
||||
original_order = list(G)
|
||||
mapping = {1: "a", 0: "b"} # partial mapping and keys out of order on purpose
|
||||
H = nx.relabel_nodes(G, mapping, copy=False)
|
||||
new_order = list(H)
|
||||
assert [mapping.get(i, i) for i in original_order] != new_order
|
||||
Loading…
Add table
Add a link
Reference in a new issue