def test_selfloops(graph_type): G = nx.complete_graph(3, create_using=graph_type) G.add_edge(0, 0) assert nodes_equal(nx.nodes_with_selfloops(G), [0]) assert edges_equal(nx.selfloop_edges(G), [(0, 0)]) assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})]) assert nx.number_of_selfloops(G) == 1
def test_selfloops_removal(graph_type): G = nx.complete_graph(3, create_using=graph_type) G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, keys=True)) G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, data=True)) G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))
def test_selfloop_edges_attr(graph_type): G = nx.complete_graph(3, create_using=graph_type) G.add_edge(0, 0) G.add_edge(1, 1, weight=2) assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, { "weight": 2 })]) assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)])
def _relabel_inplace(G, mapping): old_labels = set(mapping.keys()) new_labels = set(mapping.values()) if len(old_labels & new_labels) > 0: # labels sets overlap # can we topological sort and still do the relabeling? D = nx.DiGraph(list(mapping.items())) D.remove_edges_from(nx.selfloop_edges(D)) try: nodes = reversed(list(nx.topological_sort(D))) except nx.NetworkXUnfeasible as e: raise nx.NetworkXUnfeasible( "The node label sets are overlapping and no ordering can " "resolve the mapping. Use copy=True.") from e else: # non-overlapping label sets nodes = old_labels multigraph = G.is_multigraph() directed = G.is_directed() for old in nodes: # Test that old is in both mapping and G, otherwise ignore. try: new = mapping[old] G.add_node(new, **G.nodes[old]) except KeyError: continue if new == old: continue if multigraph: new_edges = [(new, new if old == target else target, key, data) for (_, target, key, data) in G.edges(old, data=True, keys=True)] if directed: new_edges += [ (new if old == source else source, new, key, data) for (source, _, key, data) in G.in_edges(old, data=True, keys=True) ] # Ensure new edges won't overwrite existing ones seen = set() for i, (source, target, key, data) in enumerate(new_edges): if target in G[source] and key in G[source][target]: new_key = 0 if not isinstance(key, (int, float)) else key while new_key in G[source][target] or (target, new_key) in seen: new_key += 1 new_edges[i] = (source, target, new_key, data) seen.add((target, new_key)) else: new_edges = [(new, new if old == target else target, data) for (_, target, data) in G.edges(old, data=True)] if directed: new_edges += [(new if old == source else source, new, data) for (source, _, data) in G.in_edges(old, data=True)] G.remove_node(old) G.add_edges_from(new_edges) return G
def to_scipy_sparse_array(G, nodelist=None, dtype=None, weight="weight", format="csr"): import scipy as sp import scipy.sparse # call as sp.sparse if len(G) == 0: raise nx.NetworkXError("Graph has no nodes or edges") if nodelist is None: nodelist = sorted(G) nlen = len(G) else: nlen = len(nodelist) if nlen == 0: raise nx.NetworkXError("nodelist has no nodes") nodeset = set(G.nbunch_iter(nodelist)) if nlen != len(nodeset): for n in nodelist: if n not in G: raise nx.NetworkXError(f"Node {n} in nodelist is not in G") raise nx.NetworkXError("nodelist contains duplicates.") if nlen < len(G): G = G.subgraph(nodelist) index = dict(zip(nodelist, range(nlen))) coefficients = zip( *((index[u], index[v], wt) for u, v, wt in G.edges(data=weight, default=1)) ) try: row, col, data = coefficients except ValueError: # there is no edge in the subgraph row, col, data = [], [], [] if G.is_directed(): A = sp.sparse.coo_array((data, (row, col)), shape=(nlen, nlen), dtype=dtype) else: # symmetrize matrix d = data + data r = row + col c = col + row # selfloop entries get double counted when symmetrizing # so we subtract the data on the diagonal selfloops = list(nx.selfloop_edges(G, data=weight, default=1)) if selfloops: diag_index, diag_data = zip(*((index[u], -wt) for u, v, wt in selfloops)) d += diag_data r += diag_index c += diag_index A = sp.sparse.coo_array((d, (r, c)), shape=(nlen, nlen), dtype=dtype) try: return A.asformat(format) except ValueError as err: raise nx.NetworkXError(f"Unknown sparse matrix format: {format}") from err
def test_selfloops(): graphs = [nx.Graph(), nx.DiGraph()] for graph in graphs: G = nx.complete_graph(3, create_using=graph) G.add_edge(0, 0) assert_nodes_equal(nx.nodes_with_selfloops(G), [0]) assert_edges_equal(nx.selfloop_edges(G), [(0, 0)]) assert_edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})]) assert nx.number_of_selfloops(G) == 1 # test selfloop attr G.add_edge(1, 1, weight=2) assert_edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, { "weight": 2 })]) assert_edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)]) # test removing selfloops behavior vis-a-vis altering a dict while iterating G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G)) if G.is_multigraph(): G.add_edge(0, 0) pytest.raises(RuntimeError, G.remove_edges_from, nx.selfloop_edges(G, keys=True)) G.add_edge(0, 0) pytest.raises(TypeError, G.remove_edges_from, nx.selfloop_edges(G, data=True)) G.add_edge(0, 0) pytest.raises( RuntimeError, G.remove_edges_from, nx.selfloop_edges(G, data=True, keys=True), ) else: G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, keys=True)) G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, data=True)) G.add_edge(0, 0) G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))