diff options
| author | Jarrod Millman <jarrod.millman@gmail.com> | 2019-11-19 23:12:09 -0800 |
|---|---|---|
| committer | Jarrod Millman <jarrod.millman@gmail.com> | 2019-11-19 23:36:38 -0800 |
| commit | a9daddcd6dbd3a9323ed892d8d0c8236deb37e2f (patch) | |
| tree | ed079a14afbf8c4f1b34510b26cbfee1e3576b6b | |
| parent | f34040c8e5c72294c4d9b99dad1ff515a0a06eaf (diff) | |
| download | networkx-a9daddcd6dbd3a9323ed892d8d0c8236deb37e2f.tar.gz | |
Update style
| -rw-r--r-- | networkx/algorithms/connectivity/tests/test_kcomponents.py | 204 | ||||
| -rw-r--r-- | networkx/algorithms/connectivity/tests/test_kcutsets.py | 41 | ||||
| -rw-r--r-- | networkx/algorithms/flow/tests/test_gomory_hu.py | 55 | ||||
| -rw-r--r-- | networkx/algorithms/flow/tests/test_maxflow_large_graph.py | 76 | ||||
| -rw-r--r-- | networkx/algorithms/similarity.py | 431 | ||||
| -rw-r--r-- | networkx/tests/test_all_random_functions.py | 82 | ||||
| -rw-r--r-- | networkx/tests/test_convert_pandas.py | 190 |
7 files changed, 664 insertions, 415 deletions
diff --git a/networkx/algorithms/connectivity/tests/test_kcomponents.py b/networkx/algorithms/connectivity/tests/test_kcomponents.py index f1160261..fbe111ad 100644 --- a/networkx/algorithms/connectivity/tests/test_kcomponents.py +++ b/networkx/algorithms/connectivity/tests/test_kcomponents.py @@ -14,14 +14,12 @@ from networkx.algorithms.connectivity.kcomponents import ( def torrents_and_ferraro_graph(): # Graph from https://arxiv.org/pdf/1503.04476v1 p.26 G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), - label_attribute='labels', + nx.grid_graph([5, 5]), label_attribute="labels" ) - rlabels = nx.get_node_attributes(G, 'labels') + rlabels = nx.get_node_attributes(G, "labels") labels = {v: k for k, v in rlabels.items()} - for nodes in [(labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 4)], labels[(4, 4)])]: + for nodes in [(labels[(0, 4)], labels[(1, 4)]), (labels[(3, 4)], labels[(4, 4)])]: new_node = G.order() + 1 # Petersen graph is triconnected P = nx.petersen_graph() @@ -46,8 +44,7 @@ def torrents_and_ferraro_graph(): # needed because K5s share only one node. G.add_edge(new_node + 16, new_node + 8) - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(3, 0)], labels[(4, 0)])]: + for nodes in [(labels[(0, 0)], labels[(1, 0)]), (labels[(3, 0)], labels[(4, 0)])]: new_node = G.order() + 1 # Petersen graph is triconnected P = nx.petersen_graph() @@ -137,10 +134,40 @@ def test_karate(): def test_karate_component_number(): karate_k_num = { - 0: 4, 1: 4, 2: 4, 3: 4, 4: 3, 5: 3, 6: 3, 7: 4, 8: 4, 9: 2, - 10: 3, 11: 1, 12: 2, 13: 4, 14: 2, 15: 2, 16: 2, 17: 2, - 18: 2, 19: 3, 20: 2, 21: 2, 22: 2, 23: 3, 24: 3, 25: 3, - 26: 2, 27: 3, 28: 3, 29: 3, 30: 4, 31: 3, 32: 4, 33: 4 + 0: 4, + 1: 4, + 2: 4, + 3: 4, + 4: 3, + 5: 3, + 6: 3, + 7: 4, + 8: 4, + 9: 2, + 10: 3, + 11: 1, + 12: 2, + 13: 4, + 14: 2, + 15: 2, + 16: 2, + 17: 2, + 18: 2, + 19: 3, + 20: 2, + 21: 2, + 22: 2, + 23: 3, + 24: 3, + 25: 3, + 26: 2, + 27: 3, + 28: 3, + 29: 3, + 30: 4, + 31: 3, + 32: 4, + 33: 4, } G = nx.karate_club_graph() k_components = nx.k_components(G) @@ -156,62 +183,64 @@ def test_davis_southern_women(): def test_davis_southern_women_detail_3_and_4(): solution = { - 3: [{ - 'Nora Fayette', - 'E10', - 'Myra Liddel', - 'E12', - 'E14', - 'Frances Anderson', - 'Evelyn Jefferson', - 'Ruth DeSand', - 'Helen Lloyd', - 'Eleanor Nye', - 'E9', - 'E8', - 'E5', - 'E4', - 'E7', - 'E6', - 'E1', - 'Verne Sanderson', - 'E3', - 'E2', - 'Theresa Anderson', - 'Pearl Oglethorpe', - 'Katherina Rogers', - 'Brenda Rogers', - 'E13', - 'Charlotte McDowd', - 'Sylvia Avondale', - 'Laura Mandeville', - }, + 3: [ + { + "Nora Fayette", + "E10", + "Myra Liddel", + "E12", + "E14", + "Frances Anderson", + "Evelyn Jefferson", + "Ruth DeSand", + "Helen Lloyd", + "Eleanor Nye", + "E9", + "E8", + "E5", + "E4", + "E7", + "E6", + "E1", + "Verne Sanderson", + "E3", + "E2", + "Theresa Anderson", + "Pearl Oglethorpe", + "Katherina Rogers", + "Brenda Rogers", + "E13", + "Charlotte McDowd", + "Sylvia Avondale", + "Laura Mandeville", + } ], - 4: [{ - 'Nora Fayette', - 'E10', - 'Verne Sanderson', - 'E12', - 'Frances Anderson', - 'Evelyn Jefferson', - 'Ruth DeSand', - 'Helen Lloyd', - 'Eleanor Nye', - 'E9', - 'E8', - 'E5', - 'E4', - 'E7', - 'E6', - 'Myra Liddel', - 'E3', - 'Theresa Anderson', - 'Katherina Rogers', - 'Brenda Rogers', - 'Charlotte McDowd', - 'Sylvia Avondale', - 'Laura Mandeville', - }, + 4: [ + { + "Nora Fayette", + "E10", + "Verne Sanderson", + "E12", + "Frances Anderson", + "Evelyn Jefferson", + "Ruth DeSand", + "Helen Lloyd", + "Eleanor Nye", + "E9", + "E8", + "E5", + "E4", + "E7", + "E6", + "Myra Liddel", + "E3", + "Theresa Anderson", + "Katherina Rogers", + "Brenda Rogers", + "Charlotte McDowd", + "Sylvia Avondale", + "Laura Mandeville", + } ], } G = nx.davis_southern_women_graph() @@ -227,24 +256,37 @@ def test_davis_southern_women_detail_3_and_4(): def test_set_consolidation_rosettacode(): # Tests from http://rosettacode.org/wiki/Set_consolidation def list_of_sets_equal(result, solution): - assert ( - {frozenset(s) for s in result} == - {frozenset(s) for s in solution}) - question = [{'A', 'B'}, {'C', 'D'}] - solution = [{'A', 'B'}, {'C', 'D'}] + assert {frozenset(s) for s in result} == {frozenset(s) for s in solution} + + question = [{"A", "B"}, {"C", "D"}] + solution = [{"A", "B"}, {"C", "D"}] list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'B'}, {'B', 'C'}] - solution = [{'A', 'B', 'C'}] + question = [{"A", "B"}, {"B", "C"}] + solution = [{"A", "B", "C"}] list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'B'}, {'C', 'D'}, {'D', 'B'}] - solution = [{'A', 'C', 'B', 'D'}] + question = [{"A", "B"}, {"C", "D"}, {"D", "B"}] + solution = [{"A", "C", "B", "D"}] list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}] - solution = [{'A', 'C', 'B', 'D'}, {'G', 'F', 'I', 'H', 'K'}] + question = [{"H", "I", "K"}, {"A", "B"}, {"C", "D"}, {"D", "B"}, {"F", "G", "H"}] + solution = [{"A", "C", "B", "D"}, {"G", "F", "I", "H", "K"}] list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'H'}, {'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}] - solution = [{'A', 'C', 'B', 'D', 'G', 'F', 'I', 'H', 'K'}] + question = [ + {"A", "H"}, + {"H", "I", "K"}, + {"A", "B"}, + {"C", "D"}, + {"D", "B"}, + {"F", "G", "H"}, + ] + solution = [{"A", "C", "B", "D", "G", "F", "I", "H", "K"}] list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}, {'A', 'H'}] - solution = [{'A', 'C', 'B', 'D', 'G', 'F', 'I', 'H', 'K'}] + question = [ + {"H", "I", "K"}, + {"A", "B"}, + {"C", "D"}, + {"D", "B"}, + {"F", "G", "H"}, + {"A", "H"}, + ] + solution = [{"A", "C", "B", "D", "G", "F", "I", "H", "K"}] list_of_sets_equal(_consolidate(question, 1), solution) diff --git a/networkx/algorithms/connectivity/tests/test_kcutsets.py b/networkx/algorithms/connectivity/tests/test_kcutsets.py index 492b309d..4bb07094 100644 --- a/networkx/algorithms/connectivity/tests/test_kcutsets.py +++ b/networkx/algorithms/connectivity/tests/test_kcutsets.py @@ -22,15 +22,18 @@ flow_funcs = [ # Some nice synthetic graphs ## def graph_example_1(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') + G = nx.convert_node_labels_to_integers( + nx.grid_graph([5, 5]), label_attribute="labels" + ) + rlabels = nx.get_node_attributes(G, "labels") labels = {v: k for k, v in rlabels.items()} - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 0)], labels[(4, 0)]), - (labels[(3, 4)], labels[(4, 4)])]: + for nodes in [ + (labels[(0, 0)], labels[(1, 0)]), + (labels[(0, 4)], labels[(1, 4)]), + (labels[(3, 0)], labels[(4, 0)]), + (labels[(3, 4)], labels[(4, 4)]), + ]: new_node = G.order() + 1 # Petersen graph is triconnected P = nx.petersen_graph() @@ -56,13 +59,13 @@ def graph_example_1(): def torrents_and_ferraro_graph(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') + G = nx.convert_node_labels_to_integers( + nx.grid_graph([5, 5]), label_attribute="labels" + ) + rlabels = nx.get_node_attributes(G, "labels") labels = {v: k for k, v in rlabels.items()} - for nodes in [(labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 4)], labels[(4, 4)])]: + for nodes in [(labels[(0, 4)], labels[(1, 4)]), (labels[(3, 4)], labels[(4, 4)])]: new_node = G.order() + 1 # Petersen graph is triconnected P = nx.petersen_graph() @@ -87,8 +90,7 @@ def torrents_and_ferraro_graph(): # This stupid mistake make one reviewer very angry :P G.add_edge(new_node + 16, new_node + 8) - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(3, 0)], labels[(4, 0)])]: + for nodes in [(labels[(0, 0)], labels[(1, 0)]), (labels[(3, 0)], labels[(4, 0)])]: new_node = G.order() + 1 # Petersen graph is triconnected P = nx.petersen_graph() @@ -209,8 +211,7 @@ def test_disconnected_graph(): def test_alternative_flow_functions(): - graphs = [nx.grid_2d_graph(4, 4), - nx.cycle_graph(5)] + graphs = [nx.grid_2d_graph(4, 4), nx.cycle_graph(5)] for G in graphs: node_conn = nx.node_connectivity(G) for flow_func in flow_funcs: @@ -261,13 +262,7 @@ def test_cycle_graph(): def test_complete_graph(): G = nx.complete_graph(5) - solution = [ - {0, 1, 2, 3}, - {0, 1, 2, 4}, - {0, 1, 3, 4}, - {0, 2, 3, 4}, - {1, 2, 3, 4}, - ] + solution = [{0, 1, 2, 3}, {0, 1, 2, 4}, {0, 1, 3, 4}, {0, 2, 3, 4}, {1, 2, 3, 4}] cuts = list(nx.all_node_cuts(G)) assert len(solution) == len(cuts) for cut in cuts: diff --git a/networkx/algorithms/flow/tests/test_gomory_hu.py b/networkx/algorithms/flow/tests/test_gomory_hu.py index b82a32f7..0d9ded84 100644 --- a/networkx/algorithms/flow/tests/test_gomory_hu.py +++ b/networkx/algorithms/flow/tests/test_gomory_hu.py @@ -18,10 +18,9 @@ flow_funcs = [ class TestGomoryHuTree: - def minimum_edge_weight(self, T, u, v): - path = nx.shortest_path(T, u, v, weight='weight') - return min((T[u][v]['weight'], (u, v)) for (u, v) in zip(path, path[1:])) + path = nx.shortest_path(T, u, v, weight="weight") + return min((T[u][v]["weight"], (u, v)) for (u, v) in zip(path, path[1:])) def compute_cutset(self, G, T_orig, edge): T = T_orig.copy() @@ -34,61 +33,56 @@ class TestGomoryHuTree: def test_default_flow_function_karate_club_graph(self): G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") T = nx.gomory_hu_tree(G) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) + assert nx.minimum_cut_value(G, u, v) == cut_value def test_karate_club_graph(self): G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") for flow_func in flow_funcs: T = nx.gomory_hu_tree(G, flow_func=flow_func) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) + assert nx.minimum_cut_value(G, u, v) == cut_value def test_davis_southern_women_graph(self): G = nx.davis_southern_women_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") for flow_func in flow_funcs: T = nx.gomory_hu_tree(G, flow_func=flow_func) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) + assert nx.minimum_cut_value(G, u, v) == cut_value def test_florentine_families_graph(self): G = nx.florentine_families_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") for flow_func in flow_funcs: T = nx.gomory_hu_tree(G, flow_func=flow_func) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) + assert nx.minimum_cut_value(G, u, v) == cut_value def test_les_miserables_graph_cutset(self): G = nx.les_miserables_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") for flow_func in flow_funcs: T = nx.gomory_hu_tree(G, flow_func=flow_func) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) + assert nx.minimum_cut_value(G, u, v) == cut_value def test_karate_club_graph_cutset(self): G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') + nx.set_edge_attributes(G, 1, "capacity") T = nx.gomory_hu_tree(G) assert nx.is_tree(T) u, v = 0, 33 @@ -99,18 +93,25 @@ class TestGomoryHuTree: def test_wikipedia_example(self): # Example from https://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree G = nx.Graph() - G.add_weighted_edges_from(( - (0, 1, 1), (0, 2, 7), (1, 2, 1), - (1, 3, 3), (1, 4, 2), (2, 4, 4), - (3, 4, 1), (3, 5, 6), (4, 5, 2), - )) + G.add_weighted_edges_from( + ( + (0, 1, 1), + (0, 2, 7), + (1, 2, 1), + (1, 3, 3), + (1, 4, 2), + (2, 4, 4), + (3, 4, 1), + (3, 5, 6), + (4, 5, 2), + ) + ) for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, capacity='weight', flow_func=flow_func) + T = nx.gomory_hu_tree(G, capacity="weight", flow_func=flow_func) assert nx.is_tree(T) for u, v in combinations(G, 2): cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v, capacity='weight') == - cut_value) + assert nx.minimum_cut_value(G, u, v, capacity="weight") == cut_value def test_directed_raises(self): with pytest.raises(nx.NetworkXNotImplemented): diff --git a/networkx/algorithms/flow/tests/test_maxflow_large_graph.py b/networkx/algorithms/flow/tests/test_maxflow_large_graph.py index e152cb50..dceba17b 100644 --- a/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +++ b/networkx/algorithms/flow/tests/test_maxflow_large_graph.py @@ -30,29 +30,27 @@ def gen_pyramid(N): G = nx.DiGraph() for i in range(N - 1): - cap = 1. / (i + 2) + cap = 1.0 / (i + 2) for j in range(i + 1): - G.add_edge((i, j), (i + 1, j), - capacity=cap) - cap = 1. / (i + 1) - cap - G.add_edge((i, j), (i + 1, j + 1), - capacity=cap) - cap = 1. / (i + 2) - cap + G.add_edge((i, j), (i + 1, j), capacity=cap) + cap = 1.0 / (i + 1) - cap + G.add_edge((i, j), (i + 1, j + 1), capacity=cap) + cap = 1.0 / (i + 2) - cap for j in range(N): - G.add_edge((N - 1, j), 't') + G.add_edge((N - 1, j), "t") return G def read_graph(name): dirname = os.path.dirname(__file__) - path = os.path.join(dirname, name + '.gpickle.bz2') + path = os.path.join(dirname, name + ".gpickle.bz2") return nx.read_gpickle(path) def validate_flows(G, s, t, soln_value, R, flow_func): - flow_value = R.graph['flow_value'] + flow_value = R.graph["flow_value"] flow_dict = build_flow_dict(G, R) assert soln_value == flow_value, msg.format(flow_func.__name__) assert set(G) == set(flow_dict), msg.format(flow_func.__name__) @@ -61,7 +59,9 @@ def validate_flows(G, s, t, soln_value, R, flow_func): excess = {u: 0 for u in flow_dict} for u in flow_dict: for v, flow in flow_dict[u].items(): - assert flow <= G[u][v].get('capacity', float('inf')), msg.format(flow_func.__name__) + assert flow <= G[u][v].get("capacity", float("inf")), msg.format( + flow_func.__name__ + ) assert flow >= 0, msg.format(flow_func.__name__) excess[u] -= flow excess[v] += flow @@ -75,16 +75,15 @@ def validate_flows(G, s, t, soln_value, R, flow_func): class TestMaxflowLargeGraph: - def test_complete_graph(self): N = 50 G = nx.complete_graph(N) - nx.set_edge_attributes(G, 5, 'capacity') - R = build_residual_network(G, 'capacity') + nx.set_edge_attributes(G, 5, "capacity") + R = build_residual_network(G, "capacity") kwargs = dict(residual=R) for flow_func in flow_funcs: - kwargs['flow_func'] = flow_func + kwargs["flow_func"] = flow_func flow_value = nx.maximum_flow_value(G, 1, 2, **kwargs) assert flow_value == 5 * (N - 1), msg.format(flow_func.__name__) @@ -92,56 +91,55 @@ class TestMaxflowLargeGraph: N = 10 # N = 100 # this gives a graph with 5051 nodes G = gen_pyramid(N) - R = build_residual_network(G, 'capacity') + R = build_residual_network(G, "capacity") kwargs = dict(residual=R) for flow_func in flow_funcs: - kwargs['flow_func'] = flow_func - flow_value = nx.maximum_flow_value(G, (0, 0), 't', **kwargs) - assert almost_equal(flow_value, 1.), msg.format(flow_func.__name__) + kwargs["flow_func"] = flow_func + flow_value = nx.maximum_flow_value(G, (0, 0), "t", **kwargs) + assert almost_equal(flow_value, 1.0), msg.format(flow_func.__name__) def test_gl1(self): - G = read_graph('gl1') + G = read_graph("gl1") s = 1 t = len(G) - R = build_residual_network(G, 'capacity') + R = build_residual_network(G, "capacity") kwargs = dict(residual=R) # do one flow_func to save time flow_func = flow_funcs[0] - validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), - flow_func) -# for flow_func in flow_funcs: -# validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), -# flow_func) + validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), flow_func) + + # for flow_func in flow_funcs: + # validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), + # flow_func) def test_gw1(self): - G = read_graph('gw1') + G = read_graph("gw1") s = 1 t = len(G) - R = build_residual_network(G, 'capacity') + R = build_residual_network(G, "capacity") kwargs = dict(residual=R) for flow_func in flow_funcs: - validate_flows(G, s, t, 1202018, flow_func(G, s, t, **kwargs), - flow_func) + validate_flows(G, s, t, 1202018, flow_func(G, s, t, **kwargs), flow_func) def test_wlm3(self): - G = read_graph('wlm3') + G = read_graph("wlm3") s = 1 t = len(G) - R = build_residual_network(G, 'capacity') + R = build_residual_network(G, "capacity") kwargs = dict(residual=R) # do one flow_func to save time flow_func = flow_funcs[0] - validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), - flow_func) -# for flow_func in flow_funcs: -# validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), -# flow_func) + validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), flow_func) + + # for flow_func in flow_funcs: + # validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), + # flow_func) def test_preflow_push_global_relabel(self): - G = read_graph('gw1') + G = read_graph("gw1") R = preflow_push(G, 1, len(G), global_relabel_freq=50) - assert R.graph['flow_value'] == 1202018 + assert R.graph["flow_value"] == 1202018 diff --git a/networkx/algorithms/similarity.py b/networkx/algorithms/similarity.py index 985e9500..dfd95efc 100644 --- a/networkx/algorithms/similarity.py +++ b/networkx/algorithms/similarity.py @@ -16,12 +16,12 @@ from itertools import product import networkx as nx __all__ = [ - 'graph_edit_distance', - 'optimal_edit_paths', - 'optimize_graph_edit_distance', - 'optimize_edit_paths', - 'simrank_similarity', - 'simrank_similarity_numpy', + "graph_edit_distance", + "optimal_edit_paths", + "optimize_graph_edit_distance", + "optimize_edit_paths", + "simrank_similarity", + "simrank_similarity_numpy", ] @@ -29,12 +29,19 @@ def debug_print(*args, **kwargs): print(*args, **kwargs) -def graph_edit_distance(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): +def graph_edit_distance( + G1, + G2, + node_match=None, + edge_match=None, + node_subst_cost=None, + node_del_cost=None, + node_ins_cost=None, + edge_subst_cost=None, + edge_del_cost=None, + edge_ins_cost=None, + upper_bound=None, +): """Returns GED (graph edit distance) between graphs G1 and G2. Graph edit distance is a graph similarity measure analogous to @@ -153,22 +160,38 @@ def graph_edit_distance(G1, G2, node_match=None, edge_match=None, """ bestcost = None - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, True): + for vertex_path, edge_path, cost in optimize_edit_paths( + G1, + G2, + node_match, + edge_match, + node_subst_cost, + node_del_cost, + node_ins_cost, + edge_subst_cost, + edge_del_cost, + edge_ins_cost, + upper_bound, + True, + ): # assert bestcost is None or cost < bestcost bestcost = cost return bestcost -def optimal_edit_paths(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): +def optimal_edit_paths( + G1, + G2, + node_match=None, + edge_match=None, + node_subst_cost=None, + node_del_cost=None, + node_ins_cost=None, + edge_subst_cost=None, + edge_del_cost=None, + edge_ins_cost=None, + upper_bound=None, +): """Returns all minimum-cost edit paths transforming G1 to G2. Graph edit path is a sequence of node and edge edit operations @@ -296,11 +319,20 @@ def optimal_edit_paths(G1, G2, node_match=None, edge_match=None, """ paths = list() bestcost = None - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, False): + for vertex_path, edge_path, cost in optimize_edit_paths( + G1, + G2, + node_match, + edge_match, + node_subst_cost, + node_del_cost, + node_ins_cost, + edge_subst_cost, + edge_del_cost, + edge_ins_cost, + upper_bound, + False, + ): # assert bestcost is None or cost <= bestcost if bestcost is not None and cost < bestcost: paths = list() @@ -309,12 +341,19 @@ def optimal_edit_paths(G1, G2, node_match=None, edge_match=None, return paths, bestcost -def optimize_graph_edit_distance(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): +def optimize_graph_edit_distance( + G1, + G2, + node_match=None, + edge_match=None, + node_subst_cost=None, + node_del_cost=None, + node_ins_cost=None, + edge_subst_cost=None, + edge_del_cost=None, + edge_ins_cost=None, + upper_bound=None, +): """Returns consecutive approximations of GED (graph edit distance) between graphs G1 and G2. @@ -435,20 +474,37 @@ def optimize_graph_edit_distance(G1, G2, node_match=None, edge_match=None, <10.5220/0005209202710278>. <hal-01168816> https://hal.archives-ouvertes.fr/hal-01168816 """ - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, True): + for vertex_path, edge_path, cost in optimize_edit_paths( + G1, + G2, + node_match, + edge_match, + node_subst_cost, + node_del_cost, + node_ins_cost, + edge_subst_cost, + edge_del_cost, + edge_ins_cost, + upper_bound, + True, + ): yield cost -def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None, strictly_decreasing=True): +def optimize_edit_paths( + G1, + G2, + node_match=None, + edge_match=None, + node_subst_cost=None, + node_del_cost=None, + node_ins_cost=None, + edge_subst_cost=None, + edge_del_cost=None, + edge_ins_cost=None, + upper_bound=None, + strictly_decreasing=True, +): """GED (graph edit distance) calculation: advanced interface. Graph edit path is a sequence of node and edge edit operations @@ -603,8 +659,9 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, lsa_row_ind[dummy_ind] = lsa_col_ind[subst_ind] + m lsa_col_ind[dummy_ind] = lsa_row_ind[subst_ind] + n - return CostMatrix(C, lsa_row_ind, lsa_col_ind, - C[lsa_row_ind, lsa_col_ind].sum()) + return CostMatrix( + C, lsa_row_ind, lsa_col_ind, C[lsa_row_ind, lsa_col_ind].sum() + ) def extract_C(C, i, j, m, n): # assert(C.shape == (m + n, m + n)) @@ -646,12 +703,18 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, N = len(pending_h) # assert Ce.C.shape == (M + N, M + N) - g_ind = [i for i in range(M) if pending_g[i][:2] == (u, u) or - any(pending_g[i][:2] in ((p, u), (u, p)) - for p, q in matched_uv)] - h_ind = [j for j in range(N) if pending_h[j][:2] == (v, v) or - any(pending_h[j][:2] in ((q, v), (v, q)) - for p, q in matched_uv)] + g_ind = [ + i + for i in range(M) + if pending_g[i][:2] == (u, u) + or any(pending_g[i][:2] in ((p, u), (u, p)) for p, q in matched_uv) + ] + h_ind = [ + j + for j in range(N) + if pending_h[j][:2] == (v, v) + or any(pending_h[j][:2] in ((q, v), (v, q)) for p, q in matched_uv) + ] m = len(g_ind) n = len(h_ind) @@ -666,13 +729,16 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, for l, j in zip(range(n), h_ind): h = pending_h[j][:2] if nx.is_directed(G1) or nx.is_directed(G2): - if any(g == (p, u) and h == (q, v) or - g == (u, p) and h == (v, q) - for p, q in matched_uv): + if any( + g == (p, u) and h == (q, v) or g == (u, p) and h == (v, q) + for p, q in matched_uv + ): continue else: - if any(g in ((p, u), (u, p)) and h in ((q, v), (v, q)) - for p, q in matched_uv): + if any( + g in ((p, u), (u, p)) and h in ((q, v), (v, q)) + for p, q in matched_uv + ): continue if g == (u, u): continue @@ -681,10 +747,14 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, C[k, l] = inf localCe = make_CostMatrix(C, m, n) - ij = list((g_ind[k] if k < m else M + h_ind[l], - h_ind[l] if l < n else N + g_ind[k]) - for k, l in zip(localCe.lsa_row_ind, localCe.lsa_col_ind) - if k < m or l < n) + ij = list( + ( + g_ind[k] if k < m else M + h_ind[l], + h_ind[l] if l < n else N + g_ind[k], + ) + for k, l in zip(localCe.lsa_row_ind, localCe.lsa_col_ind) + if k < m or l < n + ) else: ij = [] @@ -701,8 +771,9 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, else: return Ce - def get_edit_ops(matched_uv, pending_u, pending_v, Cv, - pending_g, pending_h, Ce, matched_cost): + def get_edit_ops( + matched_uv, pending_u, pending_v, Cv, pending_g, pending_h, Ce, matched_cost + ): """ Parameters: matched_uv: partial vertex edit path @@ -730,57 +801,86 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, # assert Cv.C.shape == (m + n, m + n) # 1) a vertex mapping from optimal linear sum assignment - i, j = min((k, l) for k, l in zip(Cv.lsa_row_ind, Cv.lsa_col_ind) - if k < m or l < n) - xy, localCe = match_edges(pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, pending_h, Ce, matched_uv) + i, j = min( + (k, l) for k, l in zip(Cv.lsa_row_ind, Cv.lsa_col_ind) if k < m or l < n + ) + xy, localCe = match_edges( + pending_u[i] if i < m else None, + pending_v[j] if j < n else None, + pending_g, + pending_h, + Ce, + matched_uv, + ) Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) # assert Ce.ls <= localCe.ls + Ce_xy.ls if prune(matched_cost + Cv.ls + localCe.ls + Ce_xy.ls): pass else: # get reduced Cv efficiently - Cv_ij = CostMatrix(reduce_C(Cv.C, (i,), (j,), m, n), - reduce_ind(Cv.lsa_row_ind, (i, m + j)), - reduce_ind(Cv.lsa_col_ind, (j, n + i)), - Cv.ls - Cv.C[i, j]) + Cv_ij = CostMatrix( + reduce_C(Cv.C, (i,), (j,), m, n), + reduce_ind(Cv.lsa_row_ind, (i, m + j)), + reduce_ind(Cv.lsa_col_ind, (j, n + i)), + Cv.ls - Cv.C[i, j], + ) yield (i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls # 2) other candidates, sorted by lower-bound cost estimate other = list() fixed_i, fixed_j = i, j if m <= n: - candidates = ((t, fixed_j) for t in range(m + n) - if t != fixed_i and (t < m or t == m + fixed_j)) + candidates = ( + (t, fixed_j) + for t in range(m + n) + if t != fixed_i and (t < m or t == m + fixed_j) + ) else: - candidates = ((fixed_i, t) for t in range(m + n) - if t != fixed_j and (t < n or t == n + fixed_i)) + candidates = ( + (fixed_i, t) + for t in range(m + n) + if t != fixed_j and (t < n or t == n + fixed_i) + ) for i, j in candidates: if prune(matched_cost + Cv.C[i, j] + Ce.ls): continue - Cv_ij = make_CostMatrix(reduce_C(Cv.C, (i,), (j,), m, n), - m - 1 if i < m else m, - n - 1 if j < n else n) + Cv_ij = make_CostMatrix( + reduce_C(Cv.C, (i,), (j,), m, n), + m - 1 if i < m else m, + n - 1 if j < n else n, + ) # assert Cv.ls <= Cv.C[i, j] + Cv_ij.ls if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + Ce.ls): continue - xy, localCe = match_edges(pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, pending_h, Ce, matched_uv) + xy, localCe = match_edges( + pending_u[i] if i < m else None, + pending_v[j] if j < n else None, + pending_g, + pending_h, + Ce, + matched_uv, + ) if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls): continue Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) # assert Ce.ls <= localCe.ls + Ce_xy.ls - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls + - Ce_xy.ls): + if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls + Ce_xy.ls): continue other.append(((i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls)) yield from sorted(other, key=lambda t: t[4] + t[1].ls + t[3].ls) - def get_edit_paths(matched_uv, pending_u, pending_v, Cv, - matched_gh, pending_g, pending_h, Ce, matched_cost): + def get_edit_paths( + matched_uv, + pending_u, + pending_v, + Cv, + matched_gh, + pending_g, + pending_h, + Ce, + matched_cost, + ): """ Parameters: matched_uv: partial vertex edit path @@ -833,8 +933,16 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, yield matched_uv, matched_gh, matched_cost else: - edit_ops = get_edit_ops(matched_uv, pending_u, pending_v, Cv, - pending_g, pending_h, Ce, matched_cost) + edit_ops = get_edit_ops( + matched_uv, + pending_u, + pending_v, + Cv, + pending_g, + pending_h, + Ce, + matched_cost, + ) for ij, Cv_ij, xy, Ce_xy, edit_cost in edit_ops: i, j = ij # assert Cv.C[i, j] + sum(Ce.C[t] for t in xy) == edit_cost @@ -848,20 +956,34 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, for x, y in xy: len_g = len(pending_g) len_h = len(pending_h) - matched_gh.append((pending_g[x] if x < len_g else None, - pending_h[y] if y < len_h else None)) + matched_gh.append( + ( + pending_g[x] if x < len_g else None, + pending_h[y] if y < len_h else None, + ) + ) sortedx = list(sorted(x for x, y in xy)) sortedy = list(sorted(y for x, y in xy)) - G = list((pending_g.pop(x) if x < len(pending_g) else None) - for x in reversed(sortedx)) - H = list((pending_h.pop(y) if y < len(pending_h) else None) - for y in reversed(sortedy)) - - yield from get_edit_paths(matched_uv, pending_u, pending_v, - Cv_ij, - matched_gh, pending_g, pending_h, - Ce_xy, - matched_cost + edit_cost) + G = list( + (pending_g.pop(x) if x < len(pending_g) else None) + for x in reversed(sortedx) + ) + H = list( + (pending_h.pop(y) if y < len(pending_h) else None) + for y in reversed(sortedy) + ) + + yield from get_edit_paths( + matched_uv, + pending_u, + pending_v, + Cv_ij, + matched_gh, + pending_g, + pending_h, + Ce_xy, + matched_cost + edit_cost, + ) # backtrack if u is not None: @@ -888,13 +1010,21 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, n = len(pending_v) C = np.zeros((m + n, m + n)) if node_subst_cost: - C[0:m, 0:n] = np.array([node_subst_cost(G1.nodes[u], G2.nodes[v]) - for u in pending_u for v in pending_v] - ).reshape(m, n) + C[0:m, 0:n] = np.array( + [ + node_subst_cost(G1.nodes[u], G2.nodes[v]) + for u in pending_u + for v in pending_v + ] + ).reshape(m, n) elif node_match: - C[0:m, 0:n] = np.array([1 - int(node_match(G1.nodes[u], G2.nodes[v])) - for u in pending_u for v in pending_v] - ).reshape(m, n) + C[0:m, 0:n] = np.array( + [ + 1 - int(node_match(G1.nodes[u], G2.nodes[v])) + for u in pending_u + for v in pending_v + ] + ).reshape(m, n) else: # all zeroes pass @@ -910,12 +1040,12 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, ins_costs = [1] * len(pending_v) # assert not n or min(ins_costs) >= 0 inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n:n + m] = np.array([del_costs[i] if i == j else inf - for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m:m + n, 0:n] = np.array([ins_costs[i] if i == j else inf - for i in range(n) for j in range(n)] - ).reshape(n, n) + C[0:m, n : n + m] = np.array( + [del_costs[i] if i == j else inf for i in range(m) for j in range(m)] + ).reshape(m, m) + C[m : m + n, 0:n] = np.array( + [ins_costs[i] if i == j else inf for i in range(n) for j in range(n)] + ).reshape(n, n) Cv = make_CostMatrix(C, m, n) # debug_print('Cv: {} x {}'.format(m, n)) # debug_print(Cv.C) @@ -928,13 +1058,21 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, n = len(pending_h) C = np.zeros((m + n, m + n)) if edge_subst_cost: - C[0:m, 0:n] = np.array([edge_subst_cost(G1.edges[g], G2.edges[h]) - for g in pending_g for h in pending_h] - ).reshape(m, n) + C[0:m, 0:n] = np.array( + [ + edge_subst_cost(G1.edges[g], G2.edges[h]) + for g in pending_g + for h in pending_h + ] + ).reshape(m, n) elif edge_match: - C[0:m, 0:n] = np.array([1 - int(edge_match(G1.edges[g], G2.edges[h])) - for g in pending_g for h in pending_h] - ).reshape(m, n) + C[0:m, 0:n] = np.array( + [ + 1 - int(edge_match(G1.edges[g], G2.edges[h])) + for g in pending_g + for h in pending_h + ] + ).reshape(m, n) else: # all zeroes pass @@ -950,12 +1088,12 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, ins_costs = [1] * len(pending_h) # assert not n or min(ins_costs) >= 0 inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n:n + m] = np.array([del_costs[i] if i == j else inf - for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m:m + n, 0:n] = np.array([ins_costs[i] if i == j else inf - for i in range(n) for j in range(n)] - ).reshape(n, n) + C[0:m, n : n + m] = np.array( + [del_costs[i] if i == j else inf for i in range(m) for j in range(m)] + ).reshape(m, m) + C[m : m + n, 0:n] = np.array( + [ins_costs[i] if i == j else inf for i in range(n) for j in range(n)] + ).reshape(n, n) Ce = make_CostMatrix(C, m, n) # debug_print('Ce: {} x {}'.format(m, n)) # debug_print(Ce.C) @@ -966,6 +1104,7 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, # initial upper-bound estimate # NOTE: should work for empty graph self.value = Cv.C.sum() + Ce.C.sum() + 1 + maxcost = MaxCost() def prune(cost): @@ -979,9 +1118,9 @@ def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, # Now go! - for vertex_path, edge_path, cost in \ - get_edit_paths([], pending_u, pending_v, Cv, - [], pending_g, pending_h, Ce, 0): + for vertex_path, edge_path, cost in get_edit_paths( + [], pending_u, pending_v, Cv, [], pending_g, pending_h, Ce, 0 + ): # assert sorted(G1.nodes) == sorted(u for u, v in vertex_path if u is not None) # assert sorted(G2.nodes) == sorted(v for u, v in vertex_path if v is not None) # assert sorted(G1.edges) == sorted(g for g, h in edge_path if g is not None) @@ -1026,8 +1165,14 @@ def _is_close(d1, d2, atolerance=0, rtolerance=0): return all(all(_is_close(d1[u][v], d2[u][v]) for v in d1[u]) for u in d1) -def simrank_similarity(G, source=None, target=None, importance_factor=0.9, - max_iterations=100, tolerance=1e-4): +def simrank_similarity( + G, + source=None, + target=None, + importance_factor=0.9, + max_iterations=100, + tolerance=1e-4, +): """Returns the SimRank similarity of nodes in the graph ``G``. SimRank is a similarity metric that says "two objects are considered @@ -1121,15 +1266,19 @@ def simrank_similarity(G, source=None, target=None, importance_factor=0.9, # These functions compute the update to the similarity value of the nodes # `u` and `v` with respect to the previous similarity values. - def avg_sim(s): return sum(newsim[w][x] for (w, x) in s) / len(s) if s else 0.0 - def sim(u, v): return importance_factor * avg_sim(list(product(G[u], G[v]))) + def avg_sim(s): + return sum(newsim[w][x] for (w, x) in s) / len(s) if s else 0.0 + + def sim(u, v): + return importance_factor * avg_sim(list(product(G[u], G[v]))) for _ in range(max_iterations): if prevsim and _is_close(prevsim, newsim, tolerance): break prevsim = newsim - newsim = {u: {v: sim(u, v) if u is not v else 1 - for v in newsim[u]} for u in newsim} + newsim = { + u: {v: sim(u, v) if u is not v else 1 for v in newsim[u]} for u in newsim + } if source is not None and target is not None: return newsim[source][target] @@ -1138,8 +1287,14 @@ def simrank_similarity(G, source=None, target=None, importance_factor=0.9, return newsim -def simrank_similarity_numpy(G, source=None, target=None, importance_factor=0.9, - max_iterations=100, tolerance=1e-4): +def simrank_similarity_numpy( + G, + source=None, + target=None, + importance_factor=0.9, + max_iterations=100, + tolerance=1e-4, +): """Calculate SimRank of nodes in ``G`` using matrices with ``numpy``. The SimRank algorithm for determining node similarity is defined in @@ -1209,6 +1364,7 @@ def simrank_similarity_numpy(G, source=None, target=None, importance_factor=0.9, # where C is the importance factor, A is the column normalized # adjacency matrix, and I is the identity matrix. import numpy as np + adjacency_matrix = nx.to_numpy_array(G) # column-normalize the ``adjacency_matrix`` @@ -1218,7 +1374,8 @@ def simrank_similarity_numpy(G, source=None, target=None, importance_factor=0.9, for _ in range(max_iterations): prevsim = np.copy(newsim) newsim = importance_factor * np.matmul( - np.matmul(adjacency_matrix.T, prevsim), adjacency_matrix) + np.matmul(adjacency_matrix.T, prevsim), adjacency_matrix + ) np.fill_diagonal(newsim, 1.0) if np.allclose(prevsim, newsim, atol=tolerance): diff --git a/networkx/tests/test_all_random_functions.py b/networkx/tests/test_all_random_functions.py index 52f2a111..0d862280 100644 --- a/networkx/tests/test_all_random_functions.py +++ b/networkx/tests/test_all_random_functions.py @@ -1,5 +1,6 @@ import pytest -np = pytest.importorskip('numpy') + +np = pytest.importorskip("numpy") import random import networkx as nx @@ -46,8 +47,8 @@ def run_all_random_functions(seed): sizes = (20, 20, 10) colors = [1, 2, 3] G = nx.barbell_graph(12, 20) - deg_sequence = in_degree_sequence = w = sequence = aseq = bseq = \ - [3, 2, 1, 3, 2, 1, 3, 2, 1, 2, 1, 2, 1] + 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) @@ -81,43 +82,58 @@ def run_all_random_functions(seed): 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.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'] + 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.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}} + 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)] + 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, .5), (10, 10, .7)] + 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) + t(nx.algorithms.bipartite.preferential_attachment_graph, aseq, p, seed=seed) def kernel_integral(u, w, z): - return (z - w) + 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]] + 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) @@ -163,13 +179,22 @@ def run_all_random_functions(seed): t(nx.random_tree, n, seed=seed) t(nx.utils.powerlaw_sequence, n, seed=seed) t(nx.utils.zipf_rv, 2.3, seed=seed) - cdist = [.2, .4, .5, .7, .9, 1.0] + 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( + 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") @@ -193,14 +218,15 @@ def test_rng_interface(): # 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!") + # 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!") + # 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() diff --git a/networkx/tests/test_convert_pandas.py b/networkx/tests/test_convert_pandas.py index 0744b100..f93af843 100644 --- a/networkx/tests/test_convert_pandas.py +++ b/networkx/tests/test_convert_pandas.py @@ -1,24 +1,23 @@ import pytest + pd = pytest.importorskip("pandas") import networkx as nx -from networkx.testing import assert_nodes_equal, assert_edges_equal, \ - assert_graphs_equal +from networkx.testing import assert_nodes_equal, assert_edges_equal, assert_graphs_equal class TestConvertPandas(object): def setup_method(self): self.rng = pd.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']) + 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) + df["b"] = b # Column label 'b' (str) self.df = df - mdf = pd.DataFrame([[4, 16, 'A', 'D']], - columns=['weight', 'cost', 0, 'b']) + mdf = pd.DataFrame([[4, 16, "A", "D"]], columns=["weight", "cost", 0, "b"]) self.mdf = df.append(mdf) def test_exceptions(self): @@ -26,98 +25,128 @@ class TestConvertPandas(object): 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"]) + 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) + 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()) + 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']) + 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']) + 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'})] + 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) - df = pd.DataFrame.from_dict({ - '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]}) - 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) + df = pd.DataFrame.from_dict( + { + "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], + } + ) + 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') + 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) + 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) + 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']) + 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',) + 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): @@ -129,11 +158,9 @@ class TestConvertPandas(object): 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') + 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) @@ -142,8 +169,9 @@ class TestConvertPandas(object): def test_from_adjacency(self): nodelist = [1, 2] - dftrue = pd.DataFrame([[1, 1], [1, 0]], dtype=int, - index=nodelist, columns=nodelist) + 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) @@ -155,7 +183,7 @@ class TestConvertPandas(object): G = nx.from_pandas_edgelist(df) assert_graphs_equal(Gtrue, G) # adjacency - adj = {1: {1: {'weight': 1}, 2: {'weight': 1}}, 2: {1: {'weight': 1}}} + adj = {1: {1: {"weight": 1}, 2: {"weight": 1}}, 2: {1: {"weight": 1}}} Gtrue = nx.Graph(adj) df = nx.to_pandas_adjacency(Gtrue, dtype=int) G = nx.from_pandas_adjacency(df) @@ -163,9 +191,11 @@ class TestConvertPandas(object): 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}} + 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) df = dftrue[["A", "C", "B"]] G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph()) |
