def gn_graph(n, kernel=None, create_using=None, seed=None): G = empty_graph(1, create_using, default=nx.DiGraph) if not G.is_directed(): raise nx.NetworkXError("create_using must indicate a Directed Graph") if kernel is None: def kernel(x): return x if n == 1: return G G.add_edge(1, 0) # get started ds = [1, 1] # degree sequence for source in range(2, n): # compute distribution from kernel and degree dist = [kernel(d) for d in ds] # choose target from discrete distribution target = discrete_sequence(1, distribution=dist, seed=seed)[0] G.add_edge(source, target) ds.append(1) # the source has only one link (degree one) ds[target] += 1 # add one to the target link degree return G
def gn_graph(n, kernel=lambda x: x, seed=None): """Return the GN (growing network) digraph with n nodes. The graph is built by adding nodes one at a time with a link to one previously added node. The target node for the link is chosen with probability based on degree. The default attachment kernel is a linear function of degree. The graph is always a (directed) tree. Example: >>> D=nx.gn_graph(10) # the GN graph >>> G=D.to_undirected() # the undirected version To specify an attachment kernel use the kernel keyword >>> D=nx.gn_graph(10,kernel=lambda x:x**1.5) # A_k=k^1.5 Reference:: @article{krapivsky-2001-organization, title = {Organization of Growing Random Networks}, author = {P. L. Krapivsky and S. Redner}, journal = {Phys. Rev. E}, volume = {63}, pages = {066123}, year = {2001}, } """ G = empty_graph(1, create_using=networkx.DiGraph()) G.name = "gn_graph(%s)" % (n) if seed is not None: random.seed(seed) if n == 1: return G G.add_edge(1, 0) # get started ds = [1, 1] # degree sequence for source in range(2, n): # compute distribution from kernel and degree dist = [kernel(d) for d in ds] # choose target from discrete distribution target = discrete_sequence(1, distribution=dist)[0] G.add_edge(source, target) ds.append(1) # the source has only one link (degree one) ds[target] += 1 # add one to the target link degree return G
def gn_graph(n,kernel=lambda x:x ,seed=None): """Return the GN (growing network) digraph with n nodes. The graph is built by adding nodes one at a time with a link to one previously added node. The target node for the link is chosen with probability based on degree. The default attachment kernel is a linear function of degree. The graph is always a (directed) tree. Example: >>> D=nx.gn_graph(10) # the GN graph >>> G=D.to_undirected() # the undirected version To specify an attachment kernel use the kernel keyword >>> D=nx.gn_graph(10,kernel=lambda x:x**1.5) # A_k=k^1.5 Reference:: @article{krapivsky-2001-organization, title = {Organization of Growing Random Networks}, author = {P. L. Krapivsky and S. Redner}, journal = {Phys. Rev. E}, volume = {63}, pages = {066123}, year = {2001}, } """ G=empty_graph(1,create_using=networkx.DiGraph()) G.name="gn_graph(%s)"%(n) if seed is not None: random.seed(seed) if n==1: return G G.add_edge(1,0) # get started ds=[1,1] # degree sequence for source in range(2,n): # compute distribution from kernel and degree dist=[kernel(d) for d in ds] # choose target from discrete distribution target=discrete_sequence(1,distribution=dist)[0] G.add_edge(source,target) ds.append(1) # the source has only one link (degree one) ds[target]+=1 # add one to the target link degree return G
def random_reference(G, niter=1, connectivity=True, seed=None): """Compute a random graph by swapping edges of a given graph. Parameters ---------- G : graph An undirected graph with 4 or more nodes. niter : integer (optional, default=1) An edge is rewired approximately `niter` times. connectivity : boolean (optional, default=True) When True, ensure connectivity for the randomized graph. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Returns ------- G : graph The randomized graph. Notes ----- The implementation is adapted from the algorithm by Maslov and Sneppen (2002) [1]_. References ---------- .. [1] Maslov, Sergei, and Kim Sneppen. "Specificity and stability in topology of protein networks." Science 296.5569 (2002): 910-913. """ if G.is_directed(): msg = "random_reference() not defined for directed graphs." raise nx.NetworkXError(msg) if len(G) < 4: raise nx.NetworkXError("Graph has less than four nodes.") from networkx.utils import cumulative_distribution, discrete_sequence local_conn = nx.connectivity.local_edge_connectivity G = G.copy() keys, degrees = zip(*G.degree()) # keys, degree cdf = cumulative_distribution(degrees) # cdf of degree nnodes = len(G) nedges = nx.number_of_edges(G) niter = niter * nedges ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) swapcount = 0 for i in range(niter): n = 0 while n < ntries: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) if ai == ci: continue # same source, skip a = keys[ai] # convert index to label c = keys[ci] # choose target uniformly from neighbors b = seed.choice(list(G.neighbors(a))) d = seed.choice(list(G.neighbors(c))) if b in [a, c, d] or d in [a, b, c]: continue # all vertices should be different # don't create parallel edges if (d not in G[a]) and (b not in G[c]): G.add_edge(a, d) G.add_edge(c, b) G.remove_edge(a, b) G.remove_edge(c, d) # Check if the graph is still connected if connectivity and local_conn(G, a, b) == 0: # Not connected, revert the swap G.remove_edge(a, d) G.remove_edge(c, b) G.add_edge(a, b) G.add_edge(c, d) else: swapcount += 1 break n += 1 return G
def lattice_reference(G, niter=1, D=None, connectivity=True, seed=None): """Latticize the given graph by swapping edges. Parameters ---------- G : graph An undirected graph with 4 or more nodes. niter : integer (optional, default=1) An edge is rewired approximatively niter times. D : numpy.array (optional, default=None) Distance to the diagonal matrix. connectivity : boolean (optional, default=True) Ensure connectivity for the latticized graph when set to True. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Returns ------- G : graph The latticized graph. Notes ----- The implementation is adapted from the algorithm by Sporns et al. [1]_. which is inspired from the original work by Maslov and Sneppen(2002) [2]_. References ---------- .. [1] Sporns, Olaf, and Jonathan D. Zwi. "The small world of the cerebral cortex." Neuroinformatics 2.2 (2004): 145-162. .. [2] Maslov, Sergei, and Kim Sneppen. "Specificity and stability in topology of protein networks." Science 296.5569 (2002): 910-913. """ import numpy as np from networkx.utils import cumulative_distribution, discrete_sequence local_conn = nx.connectivity.local_edge_connectivity if G.is_directed(): msg = "lattice_reference() not defined for directed graphs." raise nx.NetworkXError(msg) 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. G = G.copy() keys, degrees = zip(*G.degree()) # keys, degree cdf = cumulative_distribution(degrees) # cdf of degree nnodes = len(G) nedges = nx.number_of_edges(G) if D is None: D = np.zeros((nnodes, nnodes)) un = np.arange(1, nnodes) um = np.arange(nnodes - 1, 0, -1) u = np.append((0, ), np.where(un < um, un, um)) for v in range(int(np.ceil(nnodes / 2))): D[nnodes - v - 1, :] = np.append(u[v + 1:], u[:v + 1]) D[v, :] = D[nnodes - v - 1, :][::-1] niter = niter * nedges ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) swapcount = 0 for i in range(niter): n = 0 while n < ntries: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) if ai == ci: continue # same source, skip a = keys[ai] # convert index to label c = keys[ci] # choose target uniformly from neighbors b = seed.choice(list(G.neighbors(a))) d = seed.choice(list(G.neighbors(c))) bi = keys.index(b) di = keys.index(d) if b in [a, c, d] or d in [a, b, c]: continue # all vertices should be different # don't create parallel edges if (d not in G[a]) and (b not in G[c]): if D[ai, bi] + D[ci, di] >= D[ai, ci] + D[bi, di]: # only swap if we get closer to the diagonal G.add_edge(a, d) G.add_edge(c, b) G.remove_edge(a, b) G.remove_edge(c, d) # Check if the graph is still connected if connectivity and local_conn(G, a, b) == 0: # Not connected, revert the swap G.remove_edge(a, d) G.remove_edge(c, b) G.add_edge(a, b) G.add_edge(c, d) else: swapcount += 1 break n += 1 return G
def gn_graph(n, kernel=None, create_using=None, seed=None): """Returns the growing network (GN) digraph with `n` nodes. The GN graph is built by adding nodes one at a time with a link to one previously added node. The target node for the link is chosen with probability based on degree. The default attachment kernel is a linear function of the degree of a node. The graph is always a (directed) tree. Parameters ---------- n : int The number of nodes for the generated graph. kernel : function The attachment kernel. create_using : NetworkX graph constructor, optional (default DiGraph) Graph type to create. If graph instance, then cleared before populated. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Examples -------- To create the undirected GN graph, use the :meth:`~DiGraph.to_directed` method:: >>> D = nx.gn_graph(10) # the GN graph >>> G = D.to_undirected() # the undirected version To specify an attachment kernel, use the `kernel` keyword argument:: >>> D = nx.gn_graph(10, kernel=lambda x: x ** 1.5) # A_k = k^1.5 References ---------- .. [1] P. L. Krapivsky and S. Redner, Organization of Growing Random Networks, Phys. Rev. E, 63, 066123, 2001. """ G = empty_graph(1, create_using, default=nx.DiGraph) if not G.is_directed(): raise nx.NetworkXError("create_using must indicate a Directed Graph") if kernel is None: def kernel(x): return x if n == 1: return G G.add_edge(1, 0) # get started ds = [1, 1] # degree sequence for source in range(2, n): # compute distribution from kernel and degree dist = [kernel(d) for d in ds] # choose target from discrete distribution target = discrete_sequence(1, distribution=dist, seed=seed)[0] G.add_edge(source, target) ds.append(1) # the source has only one link (degree one) ds[target] += 1 # add one to the target link degree return G
def gn_graph(n,kernel=None,create_using=None,seed=None): """Return the GN digraph with n nodes. The GN (growing network) graph is built by adding nodes one at a time with a link to one previously added node. The target node for the link is chosen with probability based on degree. The default attachment kernel is a linear function of degree. The graph is always a (directed) tree. Parameters ---------- n : int The number of nodes for the generated graph. kernel : function The attachment kernel. create_using : graph, optional (default DiGraph) Return graph of this type. The instance will be cleared. seed : hashable object, optional The seed for the random number generator. Examples -------- >>> D=nx.gn_graph(10) # the GN graph >>> G=D.to_undirected() # the undirected version To specify an attachment kernel use the kernel keyword >>> D=nx.gn_graph(10,kernel=lambda x:x**1.5) # A_k=k^1.5 References ---------- .. [1] P. L. Krapivsky and S. Redner, Organization of Growing Random Networks, Phys. Rev. E, 63, 066123, 2001. """ if create_using is None: create_using = nx.DiGraph() elif not create_using.is_directed(): raise nx.NetworkXError("Directed Graph required in create_using") if kernel is None: kernel = lambda x: x if seed is not None: random.seed(seed) G=empty_graph(1,create_using) G.name="gn_graph(%s)"%(n) if n==1: return G G.add_edge(1,0) # get started ds=[1,1] # degree sequence for source in range(2,n): # compute distribution from kernel and degree dist=[kernel(d) for d in ds] # choose target from discrete distribution target=discrete_sequence(1,distribution=dist)[0] G.add_edge(source,target) ds.append(1) # the source has only one link (degree one) ds[target]+=1 # add one to the target link degree return G
def gn_graph(n, kernel=None, create_using=None, seed=None): """Return the growing network (GN) digraph with `n` nodes. The GN graph is built by adding nodes one at a time with a link to one previously added node. The target node for the link is chosen with probability based on degree. The default attachment kernel is a linear function of the degree of a node. The graph is always a (directed) tree. Parameters ---------- n : int The number of nodes for the generated graph. kernel : function The attachment kernel. create_using : NetworkX graph constructor, optional (default DiGraph) Graph type to create. If graph instance, then cleared before populated. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Examples -------- To create the undirected GN graph, use the :meth:`~DiGraph.to_directed` method:: >>> D = nx.gn_graph(10) # the GN graph >>> G = D.to_undirected() # the undirected version To specify an attachment kernel, use the `kernel` keyword argument:: >>> D = nx.gn_graph(10, kernel=lambda x: x ** 1.5) # A_k = k^1.5 References ---------- .. [1] P. L. Krapivsky and S. Redner, Organization of Growing Random Networks, Phys. Rev. E, 63, 066123, 2001. """ G = empty_graph(1, create_using, default=nx.DiGraph) if not G.is_directed(): raise nx.NetworkXError("create_using must indicate a Directed Graph") if kernel is None: def kernel(x): return x if n == 1: return G G.add_edge(1, 0) # get started ds = [1, 1] # degree sequence for source in range(2, n): # compute distribution from kernel and degree dist = [kernel(d) for d in ds] # choose target from discrete distribution target = discrete_sequence(1, distribution=dist, seed=seed)[0] G.add_edge(source, target) ds.append(1) # the source has only one link (degree one) ds[target] += 1 # add one to the target link degree return G
def test_random_number_distribution(): # smoke test only z = powerlaw_sequence(20, exponent=2.5) z = discrete_sequence(20, distribution=[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3])
def random_reference(G, n_iter=1, D=None, seed=np.random.seed(np.random.randint(0, 2**30))): """Latticize the given graph by swapping edges. Parameters ---------- G : graph An undirected graph with 4 or more nodes. n_iter : integer (optional, default=1) An edge is rewired approximatively n_iter times. D : numpy.array (optional, default=None) Distance to the diagonal matrix. Returns ------- G : graph The latticized graph. Notes ----- The implementation is adapted from the algorithm by Sporns et al. [1]_. which is inspired from the original work by Maslov and Sneppen(2002) [2]_. References ---------- .. [1] Sporns, Olaf, and Jonathan D. Zwi. "The small world of the cerebral cortex." Neuroinformatics 2.2 (2004): 145-162. .. [2] Maslov, Sergei, and Kim Sneppen. "Specificity and stability in topology of protein networks." Science 296.5569 (2002): 910-913. """ from networkx.utils import cumulative_distribution, discrete_sequence # 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 = G.copy() #keys, degrees = zip(*G.degree()) # keys, degree keys = [i for i in range(len(G))] degrees = weighted_node_degree(G) cdf = cumulative_distribution(degrees) # cdf of degree nnodes = len(G) nedges = nnodes * (nnodes - 1) // 2 # NOTE: assuming full connectivity #nedges = nx.number_of_edges(G) if D is None: D = np.zeros((nnodes, nnodes)) un = np.arange(1, nnodes) um = np.arange(nnodes - 1, 0, -1) u = np.append((0, ), np.where(un < um, un, um)) for v in range(int(np.ceil(nnodes / 2))): D[nnodes - v - 1, :] = np.append(u[v + 1:], u[:v + 1]) D[v, :] = D[nnodes - v - 1, :][::-1] n_iter = n_iter * nedges ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) swapcount = 0 for i in range(n_iter): n = 0 while n < ntries: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ai, bi, ci, di) = discrete_sequence(4, cdistribution=cdf, seed=seed) if len(set((ai, bi, ci, di))) < 4: continue # picked same node twice a = keys[ai] # convert index to label b = keys[bi] c = keys[ci] d = keys[di] # only swap if we get closer to the diagonal ab = G[a, b] cd = G[c, d] G[a, b] = cd G[b, a] = cd G[c, d] = ab G[d, c] = ab swapcount += 1 break return G
def random_reference(G, niter=1, connectivity=True, seed=None): """Compute a random graph by swapping edges of a given graph. Parameters ---------- G : graph An undirected graph with 4 or more nodes. niter : integer (optional, default=1) An edge is rewired approximately `niter` times. connectivity : boolean (optional, default=True) When True, ensure connectivity for the randomized graph. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Returns ------- G : graph The randomized graph. Notes ----- The implementation is adapted from the algorithm by Maslov and Sneppen (2002) [1]_. References ---------- .. [1] Maslov, Sergei, and Kim Sneppen. "Specificity and stability in topology of protein networks." Science 296.5569 (2002): 910-913. """ if G.is_directed(): msg = "random_reference() not defined for directed graphs." raise nx.NetworkXError(msg) if len(G) < 4: raise nx.NetworkXError("Graph has less than four nodes.") from networkx.utils import cumulative_distribution, discrete_sequence local_conn = nx.connectivity.local_edge_connectivity G = G.copy() keys, degrees = zip(*G.degree()) # keys, degree cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree nnodes = len(G) nedges = nx.number_of_edges(G) niter = niter*nedges ntries = int(nnodes*nedges/(nnodes*(nnodes-1)/2)) swapcount = 0 for i in range(niter): n = 0 while n < ntries: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) if ai == ci: continue # same source, skip a = keys[ai] # convert index to label c = keys[ci] # choose target uniformly from neighbors b = seed.choice(list(G.neighbors(a))) d = seed.choice(list(G.neighbors(c))) bi = keys.index(b) di = keys.index(d) if b in [a, c, d] or d in [a, b, c]: continue # all vertices should be different # don't create parallel edges if (d not in G[a]) and (b not in G[c]): G.add_edge(a, d) G.add_edge(c, b) G.remove_edge(a, b) G.remove_edge(c, d) # Check if the graph is still connected if connectivity and local_conn(G, a, b) == 0: # Not connected, revert the swap G.remove_edge(a, d) G.remove_edge(c, b) G.add_edge(a, b) G.add_edge(c, d) else: swapcount += 1 break n += 1 return G
def lattice_reference(G, niter=1, D=None, connectivity=True, seed=None): """Latticize the given graph by swapping edges. Parameters ---------- G : graph An undirected graph with 4 or more nodes. niter : integer (optional, default=1) An edge is rewired approximatively niter times. D : numpy.array (optional, default=None) Distance to the diagonal matrix. connectivity : boolean (optional, default=True) Ensure connectivity for the latticized graph when set to True. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Returns ------- G : graph The latticized graph. Notes ----- The implementation is adapted from the algorithm by Sporns et al. [1]_. which is inspired from the original work by Maslov and Sneppen(2002) [2]_. References ---------- .. [1] Sporns, Olaf, and Jonathan D. Zwi. "The small world of the cerebral cortex." Neuroinformatics 2.2 (2004): 145-162. .. [2] Maslov, Sergei, and Kim Sneppen. "Specificity and stability in topology of protein networks." Science 296.5569 (2002): 910-913. """ import numpy as np from networkx.utils import cumulative_distribution, discrete_sequence local_conn = nx.connectivity.local_edge_connectivity if G.is_directed(): msg = "lattice_reference() not defined for directed graphs." raise nx.NetworkXError(msg) 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. G = G.copy() keys, degrees = zip(*G.degree()) # keys, degree cdf = cumulative_distribution(degrees) # cdf of degree nnodes = len(G) nedges = nx.number_of_edges(G) if D is None: D = np.zeros((nnodes, nnodes)) un = np.arange(1, nnodes) um = np.arange(nnodes - 1, 0, -1) u = np.append((0,), np.where(un < um, un, um)) for v in range(int(np.ceil(nnodes / 2))): D[nnodes - v - 1, :] = np.append(u[v + 1:], u[:v + 1]) D[v, :] = D[nnodes - v - 1, :][::-1] niter = niter*nedges ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) swapcount = 0 for i in range(niter): n = 0 while n < ntries: # pick two random edges without creating edge list # choose source node indices from discrete distribution (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) if ai == ci: continue # same source, skip a = keys[ai] # convert index to label c = keys[ci] # choose target uniformly from neighbors b = seed.choice(list(G.neighbors(a))) d = seed.choice(list(G.neighbors(c))) bi = keys.index(b) di = keys.index(d) if b in [a, c, d] or d in [a, b, c]: continue # all vertices should be different # don't create parallel edges if (d not in G[a]) and (b not in G[c]): if D[ai, bi] + D[ci, di] >= D[ai, ci] + D[bi, di]: # only swap if we get closer to the diagonal G.add_edge(a, d) G.add_edge(c, b) G.remove_edge(a, b) G.remove_edge(c, d) # Check if the graph is still connected if connectivity and local_conn(G, a, b) == 0: # Not connected, revert the swap G.remove_edge(a, d) G.remove_edge(c, b) G.add_edge(a, b) G.add_edge(c, d) else: swapcount += 1 break n += 1 return G
def connected_double_edge_swap_with_birthday_check(G, nswap=1): """ Completes nswap double-edge swaps on the graph G. A double-edge swap removes two randomly chosen edges u->v and x->y and creates the new edges u->x and y->v, provided this move retains the 'birthday' ordering of the nodes in the original edges. Parameters G=A directed graph, nswap : integer = Number of successful double-edge swaps to perform. Returns The number of successful swaps """ # uncomment below if want to ensure connectedness of initial graph. This should be true anyway for all our models/data, unless edge removal used # if not nx.is_connected(G): # raise nx.NetworkXError("Graph not connected") # if len(G) < 4: # raise nx.NetworkXError("Graph has less than four nodes.") n = 0 swapcount = 0 deg = G.in_degree() dk = list(deg.keys()) # Label key for nodes cdf = utils.cumulative_distribution(list(G.in_degree().values())) window = 1 while swapcount < nswap: wcount = 0 swapped = [] while wcount < window and swapcount < nswap: # Pick two random edges without creating edge list # Choose source nodes from discrete degree distribution (ui, xi) = utils.discrete_sequence(2, cdistribution=cdf) if ui == xi: continue # same source u = dk[ui] # convert index to label x = dk[xi] # Choose targets uniformly from neighbors u_neighbors = G.neighbors(u) x_neighbors = G.neighbors(x) if len(u_neighbors) != 0 and len(x_neighbors) != 0: v = random.choice(u_neighbors) y = random.choice(x_neighbors) if v == y: continue # same target if models.birthday_check(G, x, v) == False or models.birthday_check(G, u, y) == False: print "birthday condition not met" continue else: if (not G.has_edge(x, v)) and (not G.has_edge(u, y)): G.remove_edge(u, v) G.remove_edge(x, y) G.add_edge(x, v) G.add_edge(u, y) swapped.append((u, v, x, y)) swapcount += 1 print "swapcount is = ", swapcount n += 1 wcount += 1 # uncomment below if want to ensure connectedness of final graph, is this necessary? WIll be for some measures, but not for k_in...? # UG=G.to_undirected() # if nx.is_connected(UG): # window+=1 # else: # "graph has become disconnected, undoing changes that caused this" # # not connected, undo changes from previous window, decrease window # while swapped: # (u,v,x,y)=swapped.pop() # G.add_edge(u,v) # G.add_edge(x,y) # G.remove_edge(u,x) # G.remove_edge(v,y) # swapcount-=1 # window = int(math.ceil(float(window)/2)) # print "swapcount = " , swapcount return swapcount