def _community(G, u, community): """Get the community of the given node.""" node_u = G.nodes[u] try: return node_u[community] except KeyError as e: raise nx.NetworkXAlgorithmError("No community information") from e
def predict(u, v): if u == v: raise nx.NetworkXAlgorithmError("Self links are not supported") path_len = spl[u].get(v, inf) return alpha * sum(1 for _ in nx.common_neighbors(G, u, v)) + ( 1 - alpha) * (G.number_of_nodes() / path_len)
def bipartite_double_edge_swap(B, genes, samples, nswap=1, max_tries=1e75): """A modified version of bipartite_double_edge_swap function from multi Dendrix, which is a modified version of double_edge_swap in NetworkX to preserve the bipartite structure of the graph. :param B: nx.Graph B(G, S) a bipartite graph :param genes: list of genes G :param samples: list of samples S :param nswap: int, number of double edge swap to perform :param max_tries:int, maximum number of attests to swap edges :return: nx.Graph, permuted graph """ if nswap > max_tries: raise nx.NetworkXError("Number of swaps > number of tries allowed.") if len(B) < 4: raise nx.NetworkXError("Graph has less than four nodes.") # Instead of choosing uniformly at random from a generated edge list, # this algorithm chooses nonuniformly from the set of nodes with # probability weighted by degree. n = 0 swapcount = 0 gkeys, gdegrees = zip(*B.degree(genes).items()) # keys, degree for genes gcdf = nx.utils.cumulative_distribution( gdegrees) # cdf of degree for genes pkeys, pdegrees = zip( *B.degree(samples).items()) # keys, degree for samples pcdf = nx.utils.cumulative_distribution( pdegrees) # cdf of degree for samples while swapcount < nswap: # pick two random edges without creating edge list # choose source node indices from discrete distribution gi = nx.utils.discrete_sequence(1, cdistribution=gcdf) pi = nx.utils.discrete_sequence(1, cdistribution=pcdf) gene1 = gkeys[gi[0]] # convert index to label sample1 = pkeys[pi[0]] sample2 = random.choice(list(B[gene1])) gene2 = random.choice(list(B[sample1])) # don't create parallel edges if (gene1 not in B[sample1]) and (gene2 not in B[sample2]): B.add_edge(gene1, sample1) B.add_edge(gene2, sample2) B.remove_edge(gene1, sample2) B.remove_edge(gene2, sample1) swapcount += 1 if n >= max_tries: e = ('Maximum number of swap attempts (%s) exceeded ' % n + 'before desired swaps achieved (%s).' % nswap) raise nx.NetworkXAlgorithmError(e) n += 1 if n % 10000 == 0: logging.debug("%d swaps..\n" % n) return B
def directed_double_edge_swap(self, G, nswap=1, max_tries=100, seed=None): # u--v u--y instead of: u--v u v # becomes becomes | | # x--y x--v x--y x y np.random.seed(0) if nswap > max_tries: raise nx.NetworkXError( "Number of swaps > number of tries allowed.") if len(G) < 4: raise nx.NetworkXError("Graph has less than four nodes.") # Instead of choosing uniformly at random from a generated edge list, # this algorithm chooses nonuniformly from the set of nodes with # probability weighted by degree. n = 0 swapcount = 0 keys, degrees = zip(*G.out_degree()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree discrete_sequence = nx.utils.discrete_sequence while (swapcount < nswap): # if random.random() < 0.5: continue # trick to avoid periodicities? # pick two random edges without creating edge list # choose source node indices from discrete distribution (ui, xi) = discrete_sequence(2, cdistribution=cdf) if (ui == xi): continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] # ignore nodes with no downstream partners if ((len(G[u]) == 0) | (len(G[x]) == 0)): continue # choose target uniformly from neighbors v = np.random.choice(list(G[u])) y = np.random.choice(list(G[x])) if (v == y): continue # same target, skip if (y not in G[u]) and ( v not in G[x]): # don't create parallel edges G.add_edge(u, y, weight=G[u][v]['weight'], edge_type=G[u][v]['edge_type']) G.add_edge(x, v, weight=G[x][y]['weight'], edge_type=G[x][y]['edge_type']) G.remove_edge(u, v) G.remove_edge(x, y) swapcount += 1 if (n >= max_tries): e = (f"Maximum number of swap attempts ({n}) exceeded " f"before desired swaps achieved ({nswap}).") raise nx.NetworkXAlgorithmError(e) n += 1 return G
def double_edge_swap_outedges(G, mod_nodes, indegree_list, outdegree_list, nswap, max_tries): """Randomizes between-modul edges of the graph. This function is similiar to the generic double-edge-swap technique with an additonal constraint: Swaps that create within-module edges are not allowed.""" if len(G) < 4: raise nx.NetworkXError("Graph has less than four nodes.") n = 0 swapcount = 0 # Modified by urkang, 191117 temp_dict = dict(G.degree()) # for nodes, degree keys = list(temp_dict.keys()) degrees = list(temp_dict.values()) cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree while swapcount < nswap: (ui, xi) = nx.utils.discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] u_mod = [module for module in mod_nodes if u in mod_nodes[module]] u_mod = u_mod[0] if x in mod_nodes[u_mod]: continue # same module, skip # choose target uniformly from neighbors v = rnd.choice(list(G[u])) y = rnd.choice(list(G[x])) v_mod = [module for module in mod_nodes if v in mod_nodes[module]] v_mod = v_mod[0] if v == y or y in mod_nodes[v_mod]: continue # same target or same module, skip if (x not in G[u]) and (y not in G[v]): # don't create parallel edges if (indegree_list[u] + indegree_list[x] != 0) and (indegree_list[v] + indegree_list[y] != 0): G.add_edge(u, x) G.add_edge(v, y) G.remove_edge(u, v) G.remove_edge(x, y) swapcount += 1 if n >= max_tries: e = ('Maximum number of swap attempts (%s) exceeded ' % n + 'before desired swaps achieved (%s).' % nswap) raise nx.NetworkXAlgorithmError(e) n += 1 return G
def bipartite_double_edge_swap(G, genes, patients, nswap=1, max_tries=1e75): """A modified version of the double_edge_swap function in NetworkX to preserve the bipartite structure of the graph. For more details on this function, please see the `original NetworkX function <http://goo.gl/wWxBD>`_ that I shamelessly used to make this one. The only major change here is that I ensure that u,v and x,y are of the same type (i.e. genes or patients). """ if nswap>max_tries: raise nx.NetworkXError("Number of swaps > number of tries allowed.") if len(G) < 4: raise nx.NetworkXError("Graph has less than four nodes.") # Instead of choosing uniformly at random from a generated edge list, # this algorithm chooses nonuniformly from the set of nodes with # probability weighted by degree. n=0 swapcount=0 keys,degrees=zip(*G.degree().items()) # keys, degree cdf=nx.utils.cumulative_distribution(degrees) # cdf of degree while swapcount < nswap: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ui,xi)=nx.utils.discrete_sequence(2,cdistribution=cdf) if ui==xi: continue # same source, skip u=keys[ui] # convert index to label x=keys[xi] if (u in genes and x in genes) or (u in patients and x in patients): continue # both are genes, skip patient1 = u if u in patients else x gene1 = x if x in genes else u # choose target uniformly from neighbors patient2=random.choice( list(G[gene1]) ) gene2=random.choice( list(G[patient1]) ) # don't create parallel edges if (gene1 not in G[patient1]) and (gene2 not in G[patient2]): G.add_edge(gene1,patient1) G.add_edge(gene2,patient2) G.remove_edge(gene1,patient2) G.remove_edge(patient1, gene2) swapcount+=1 if n >= max_tries: e=('Maximum number of swap attempts (%s) exceeded '%n + 'before desired swaps achieved (%s).'%nswap) raise nx.NetworkXAlgorithmError(e) n+=1 return G
def sign_network_positive_swap(G0, nswap=1, max_tries=100): # Instead of choosing uniformly at random from a generated edge list, # this algorithm chooses nonuniformly from the set of nodes with # probability weighted by degree. G = copy.deepcopy(G0) n = 0 swapcount = 0 keys, degrees = zip(*G.degree().items()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree while swapcount < nswap: # if random.random() < 0.5: continue # trick to avoid periodicities? # pick two random edges without creating edge list # choose source node indices from discrete distribution (ui, xi) = nx.utils.discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] # choose target uniformly from neighbors if len(list(G[u])) > 0 and len(list(G[x])) > 0: v = random.choice(list(G[u])) y = random.choice(list(G[x])) if v == y: continue else: continue if (x not in G[u]) and (y not in G[v]) and G[u][v]['weight'] == 1 and G[x][y]['weight'] == 1: if ((u in G[x]) and (G[x][u]['weight'] == 2)) or ((v in G[y]) and (G[y][v]['weight'] == 2)): continue else: G.add_edge(u, x, weight=1) G.add_edge(v, y, weight=1) G.remove_edge(u, v) G.remove_edge(x, y) swapcount += 1 if n >= max_tries: e = ('Maximum number of swap attempts (%s) exceeded ' % n + 'before desired swaps achieved (%s).' % nswap) print nx.NetworkXAlgorithmError(e) break n += 1 if n % 100000 == 0: print 'swap times=', swapcount, 'try times=', n return G
def sign_network_positive_swap(G0, nswap=1, max_tries=100): G = copy.deepcopy(G0) n = 0 swapcount = 0 keys, degrees = zip(*G.degree().items()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree while swapcount < nswap: (ui, xi) = nx.utils.discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] # choose target uniformly from neighbors if len(list(G[u])) > 0 and len(list(G[x])) > 0: v = random.choice(list(G[u])) y = random.choice(list(G[x])) if v == y: continue else: continue if (x not in G[u]) and (y not in G[v]) and G[u][v]['weight'] == 1 and G[x][y]['weight'] == 1: if connected == 1: # 判断是否需要保持联通特性,为1的话则需要保持该特性 if not nx.is_connected(G): #保证网络是全联通的:若网络不是全联通网络,则撤回交换边的操作 G.add_edge(u,v) G.add_edge(x,y) G.remove_edge(u,y) G.remove_edge(x,v) continue swapcount=swapcount+1 G.add_edge(u,x,weight=1) G.add_edge(v,y,weight=1) G.remove_edge(u,v) G.remove_edge(x,y) swapcount+=1 if n >= max_tries: e=('Maximum number of swap attempts (%s) exceeded '%n + 'before desired swaps achieved (%s).'%nswap) print nx.NetworkXAlgorithmError(e) break n+=1 if n%1000000==0: print 'swap times=',swapcount,'try times=',n
def within_inter_cluster(G, ebunch=None, delta=0.001, community="community"): """Compute the ratio of within- and inter-cluster common neighbors of all node pairs in ebunch. For two nodes `u` and `v`, if a common neighbor `w` belongs to the same community as them, `w` is considered as within-cluster common neighbor of `u` and `v`. Otherwise, it is considered as inter-cluster common neighbor of `u` and `v`. The ratio between the size of the set of within- and inter-cluster common neighbors is defined as the WIC measure. [1]_ Parameters ---------- G : graph A NetworkX undirected graph. ebunch : iterable of node pairs, optional (default = None) The WIC measure will be computed for each pair of nodes given in the iterable. The pairs must be given as 2-tuples (u, v) where u and v are nodes in the graph. If ebunch is None then all non-existent edges in the graph will be used. Default value: None. delta : float, optional (default = 0.001) Value to prevent division by zero in case there is no inter-cluster common neighbor between two nodes. See [1]_ for details. Default value: 0.001. community : string, optional (default = 'community') Nodes attribute name containing the community information. G[u][community] identifies which community u belongs to. Each node belongs to at most one community. Default value: 'community'. Returns ------- piter : iterator An iterator of 3-tuples in the form (u, v, p) where (u, v) is a pair of nodes and p is their WIC measure. Examples -------- >>> G = nx.Graph() >>> G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 4), (2, 4), (3, 4)]) >>> G.nodes[0]['community'] = 0 >>> G.nodes[1]['community'] = 1 >>> G.nodes[2]['community'] = 0 >>> G.nodes[3]['community'] = 0 >>> G.nodes[4]['community'] = 0 >>> preds = nx.within_inter_cluster(G, [(0, 4)]) >>> for u, v, p in preds: ... print(f'({u}, {v}) -> {p:.8f}') (0, 4) -> 1.99800200 >>> preds = nx.within_inter_cluster(G, [(0, 4)], delta=0.5) >>> for u, v, p in preds: ... print(f'({u}, {v}) -> {p:.8f}') (0, 4) -> 1.33333333 References ---------- .. [1] Jorge Carlos Valverde-Rebaza and Alneu de Andrade Lopes. Link prediction in complex networks based on cluster information. In Proceedings of the 21st Brazilian conference on Advances in Artificial Intelligence (SBIA'12) https://doi.org/10.1007/978-3-642-34459-6_10 """ if delta <= 0: raise nx.NetworkXAlgorithmError("Delta must be greater than zero") def predict(u, v): Cu = _community(G, u, community) Cv = _community(G, v, community) if Cu != Cv: return 0 cnbors = set(nx.common_neighbors(G, u, v)) within = {w for w in cnbors if _community(G, w, community) == Cu} inter = cnbors - within return len(within) / (len(inter) + delta) return _apply_prediction(G, predict, ebunch)
def double_edge_swap(G, nswap=1, max_tries=100): """Swap two edges in the graph while keeping the node degrees fixed. A double-edge swap removes two randomly chosen edges u-v and x-y and creates the new edges u-x and v-y:: u--v u v becomes | | x--y x y If either the edge u-x or v-y already exist no swap is performed and another attempt is made to find a suitable edge pair. Parameters ---------- G : graph A NetworkX (undirected) Graph. nswap : integer (optional) Number of double-edge swaps to perform max_tries : integer (optional) Maximum number of attempts to swap nswap edges. Returns ------- G : graph The graph after nswap double edge swaps. Notes ----- Does not enforce any connectivity constraints. The graph G is modified in place. """ if G.is_directed(): raise nx.NetworkXError(\ "double_edge_swap() not defined for directed graphs.") # Instead of choosing uniformly at random from a generated edge list, # this algorithm chooses nonuniformly from the set of nodes with # probability weighted by degree. n = 0 swapcount = 0 keys, degrees = zip(*G.degree().items()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree if len(cdf) < 4: raise nx.NetworkXError("Graph has less than four nodes.") while swapcount < nswap: # if random.random() < 0.5: continue # trick to avoid periodicities? # pick two randon edges without creating edge list # choose source node indices from discrete distribution (ui, xi) = nx.utils.discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] # choose target uniformly from neighbors v = random.choice(list(G[u])) y = random.choice(list(G[x])) if v == y: continue # same target, skip if (x not in G[u]) and (y not in G[v]): # don't create parallel edges G.add_edge(u, x) G.add_edge(v, y) G.remove_edge(u, v) G.remove_edge(x, y) swapcount += 1 if n > max_tries: e = ('Maximum number of swap attempts (%s) exceeded ' % n + 'before desired swaps achieved (%s).' % nswap) raise nx.NetworkXAlgorithmError(e) n += 1 return G
def equitable_color(G, num_colors): """Provides equitable (r + 1)-coloring for nodes of G in O(r * n^2) time if deg(G) <= r. The algorithm is described in [1]_. Attempts to color a graph using r colors, where no neighbors of a node can have same color as the node itself and the number of nodes with each color differ by at most 1. Parameters ---------- G : networkX graph The nodes of this graph will be colored. num_colors : number of colors to use This number must be at least one more than the maximum degree of nodes in the graph. Returns ------- A dictionary with keys representing nodes and values representing corresponding coloring. Examples -------- >>> G = nx.cycle_graph(4) >>> d = nx.coloring.equitable_color(G, num_colors=3) >>> nx.algorithms.coloring.equitable_coloring.is_equitable(G, d) True Raises ------ NetworkXAlgorithmError If the maximum degree of the graph ``G`` is greater than ``num_colors``. References ---------- .. [1] Kierstead, H. A., Kostochka, A. V., Mydlarz, M., & Szemerédi, E. (2010). A fast algorithm for equitable coloring. Combinatorica, 30(2), 217-224. """ # Map nodes to integers for simplicity later. nodes_to_int = {} int_to_nodes = {} for idx, node in enumerate(G.nodes): nodes_to_int[node] = idx int_to_nodes[idx] = node G = nx.relabel_nodes(G, nodes_to_int, copy=True) # Basic graph statistics and sanity check. if len(G.nodes) > 0: r_ = max([G.degree(node) for node in G.nodes]) else: r_ = 0 if r_ >= num_colors: raise nx.NetworkXAlgorithmError( f"Graph has maximum degree {r_}, needs " f"{r_ + 1} (> {num_colors}) colors for guaranteed coloring.") # Ensure that the number of nodes in G is a multiple of (r + 1) pad_graph(G, num_colors) # Starting the algorithm. # L = {node: list(G.neighbors(node)) for node in G.nodes} L_ = {node: [] for node in G.nodes} # Arbitrary equitable allocation of colors to nodes. F = {node: idx % num_colors for idx, node in enumerate(G.nodes)} C = make_C_from_F(F) # The neighborhood is empty initially. N = make_N_from_L_C(L_, C) # Currently all nodes witness all edges. H = make_H_from_C_N(C, N) # Start of algorithm. edges_seen = set() for u in sorted(G.nodes): for v in sorted(G.neighbors(u)): # Do not double count edges if (v, u) has already been seen. if (v, u) in edges_seen: continue edges_seen.add((u, v)) L_[u].append(v) L_[v].append(u) N[(u, F[v])] += 1 N[(v, F[u])] += 1 if F[u] != F[v]: # Were 'u' and 'v' witnesses for F[u] -> F[v] or F[v] -> F[u]? if N[(u, F[v])] == 1: H[F[u], F[v]] -= 1 # u cannot witness an edge between F[u], F[v] if N[(v, F[u])] == 1: H[F[v], F[u]] -= 1 # v cannot witness an edge between F[v], F[u] if N[(u, F[u])] != 0: # Find the first color where 'u' does not have any neighbors. Y = [k for k in C.keys() if N[(u, k)] == 0][0] X = F[u] change_color(u, X, Y, N=N, H=H, F=F, C=C, L=L_) # Procedure P procedure_P(V_minus=X, V_plus=Y, N=N, H=H, F=F, C=C, L=L_) return {int_to_nodes[x]: F[x] for x in int_to_nodes}
def triad_type(G): """Returns the sociological triad type for a triad. Parameters ---------- G : digraph A NetworkX DiGraph with 3 nodes Returns ------- triad_type : str A string identifying the triad type Notes ----- There can be 6 unique edges in a triad (order-3 DiGraph) (so 2^^6=64 unique triads given 3 nodes). These 64 triads each display exactly 1 of 16 topologies of triads (topologies can be permuted). These topologies are identified by the following notation: {m}{a}{n}{type} (for example: 111D, 210, 102) Here: {m} = number of mutual ties (takes 0, 1, 2, 3); a mutual tie is (0,1) AND (1,0) {a} = number of assymmetric ties (takes 0, 1, 2, 3); an assymmetric tie is (0,1) BUT NOT (1,0) or vice versa {n} = number of null ties (takes 0, 1, 2, 3); a null tie is NEITHER (0,1) NOR (1,0) {type} = a letter (takes U, D, C, T) corresponding to up, down, cyclical and transitive. This is only used for topologies that can have more than one form (eg: 021D and 021U). References ---------- .. [1] Snijders, T. (2012). "Transitivity and triads." University of Oxford. http://www.stats.ox.ac.uk/snijders/Trans_Triads_ha.pdf """ if not is_triad(G): raise nx.NetworkXAlgorithmError("G is not a triad (order-3 DiGraph)") num_edges = len(G.edges()) if num_edges == 0: return "003" elif num_edges == 1: return "012" elif num_edges == 2: e1, e2 = G.edges() if set(e1) == set(e2): return "102" elif e1[0] == e2[0]: return "021D" elif e1[1] == e2[1]: return "021U" elif e1[1] == e2[0] or e2[1] == e1[0]: return "021C" elif num_edges == 3: for (e1, e2, e3) in permutations(G.edges(), 3): if set(e1) == set(e2): if e3[0] in e1: return "111U" # e3[1] in e1: return "111D" elif set(e1).symmetric_difference(set(e2)) == set(e3): if {e1[0], e2[0], e3[0]} == {e1[0], e2[0], e3[0]} == set(G.nodes()): return "030C" # e3 == (e1[0], e2[1]) and e2 == (e1[1], e3[1]): return "030T" elif num_edges == 4: for (e1, e2, e3, e4) in permutations(G.edges(), 4): if set(e1) == set(e2): # identify pair of symmetric edges (which necessarily exists) if set(e3) == set(e4): return "201" if {e3[0]} == {e4[0]} == set(e3).intersection(set(e4)): return "120D" if {e3[1]} == {e4[1]} == set(e3).intersection(set(e4)): return "120U" if e3[1] == e4[0]: return "120C" elif num_edges == 5: return "210" elif num_edges == 6: return "300"
def rewire_graph(graph, error): """ Returns a rewired copy of the original graph. The rewiring procedure preserves degree of each node. The number of rewirings is the square of the node amount. This ensures the network is completely randomized. The weight of the edges also needs to be normalized. Therefore, after the network is randomized, weight is sampled from the original graph and added to the randomized graph. Because this does not take negative / positive hubs into account, the fraction of positive / negative weights per node is not preserved. Part of the rewire_graph function has been adapted from the original NetworkX double_edge_swap function. The adapted version also swaps edge weights. License ======= NetworkX is distributed with the 3-clause BSD license. :: Copyright (C) 2004-2018, NetworkX Developers Aric Hagberg <*****@*****.**> Dan Schult <*****@*****.**> Pieter Swart <*****@*****.**> All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the NetworkX Developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Parameters ---------- :param graph: Original graph to rewire. :param error: Fraction of edges to rewire. :return: Rewired NetworkX graph """ model = graph.copy(as_view=False).to_undirected(as_view=False) swaps = round(len(model.nodes) * error) swapfail = False max_tries = len(model.nodes) * 10 try: n = 0 swapcount = 0 keys, degrees = zip(*model.degree()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree discrete_sequence = nx.utils.discrete_sequence while swapcount < swaps: # if random.random() < 0.5: continue # trick to avoid periodicities? # pick two random edges without creating edge list # choose source node indices from discrete distribution (ui, xi) = discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source, skip u = keys[ui] # convert index to label x = keys[xi] # choose target uniformly from neighbors v = choice(list(model[u])) y = choice(list(model[x])) if v == y: continue # same target, skip if (x not in model[u]) and (y not in model[v]): # don't create parallel edges weight_uv = model.edges[u, v]['weight'] weight_xy = model.edges[x, y]['weight'] model.add_edge(u, x) model.edges[u, x]['weight'] = weight_uv model.add_edge(v, y) model.edges[v, y]['weight'] = weight_xy model.remove_edge(u, v) model.remove_edge(x, y) swapcount += 1 if n >= max_tries: e = ('Maximum number of swap attempts (%s) exceeded ' % n + 'before desired swaps achieved (%s).' % swaps) raise nx.NetworkXAlgorithmError(e) n += 1 except nx.exception.NetworkXAlgorithmError: logger.error('Cannot permute this network fraction. ' + '\n' + 'Please choose a lower error parameter, or avoid calculating a centrality score. ', exc_info=True) swapfail = True # edge_weights = list() # for edge in graph.edges: # edge_weights.append(graph[edge[0]][edge[1]]['weight']) # random_weights = dict() # for edge in model.edges: # random_weights[edge] = choice(edge_weights) # nx.set_edge_attributes(model, random_weights, 'weight') return model, swapfail
def predict(u, v): if u == v: raise nx.NetworkXAlgorithmError("Self links are not supported") return sum(1 for _ in nx.common_neighbors(G, u, v))