"""Functions for generating graphs based on the "duplication" method.These graph generators start with a small initial graph then duplicatenodes and (partially) duplicate their edges. These functions aregenerally inspired by biological networks."""importnetworkxasnxfromnetworkx.utilsimportpy_random_statefromnetworkx.exceptionimportNetworkXError__all__=["partial_duplication_graph","duplication_divergence_graph"]
[docs]@py_random_state(4)defpartial_duplication_graph(N,n,p,q,seed=None):"""Returns a random graph using the partial duplication model. Parameters ---------- N : int The total number of nodes in the final graph. n : int The number of nodes in the initial clique. p : float The probability of joining each neighbor of a node to the duplicate node. Must be a number in the between zero and one, inclusive. q : float The probability of joining the source node to the duplicate node. Must be a number in the between zero and one, inclusive. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Notes ----- A graph of nodes is grown by creating a fully connected graph of size `n`. The following procedure is then repeated until a total of `N` nodes have been reached. 1. A random node, *u*, is picked and a new node, *v*, is created. 2. For each neighbor of *u* an edge from the neighbor to *v* is created with probability `p`. 3. An edge from *u* to *v* is created with probability `q`. This algorithm appears in [1]. This implementation allows the possibility of generating disconnected graphs. References ---------- .. [1] Knudsen Michael, and Carsten Wiuf. "A Markov chain approach to randomly grown graphs." Journal of Applied Mathematics 2008. <https://doi.org/10.1155/2008/190836> """ifp<0orp>1orq<0orq>1:msg="partial duplication graph must have 0 <= p, q <= 1."raiseNetworkXError(msg)ifn>N:raiseNetworkXError("partial duplication graph must have n <= N.")G=nx.complete_graph(n)fornew_nodeinrange(n,N):# Pick a random vertex, u, already in the graph.src_node=seed.randint(0,new_node-1)# Add a new vertex, v, to the graph.G.add_node(new_node)# For each neighbor of u...forneighbor_nodeinlist(nx.all_neighbors(G,src_node)):# Add the neighbor to v with probability p.ifseed.random()<p:G.add_edge(new_node,neighbor_node)# Join v and u with probability q.ifseed.random()<q:G.add_edge(new_node,src_node)returnG
[docs]@py_random_state(2)defduplication_divergence_graph(n,p,seed=None):"""Returns an undirected graph using the duplication-divergence model. A graph of `n` nodes is created by duplicating the initial nodes and retaining edges incident to the original nodes with a retention probability `p`. Parameters ---------- n : int The desired number of nodes in the graph. p : float The probability for retaining the edge of the replicated node. seed : integer, random_state, or None (default) Indicator of random number generation state. See :ref:`Randomness<randomness>`. Returns ------- G : Graph Raises ------ NetworkXError If `p` is not a valid probability. If `n` is less than 2. Notes ----- This algorithm appears in [1]. This implementation disallows the possibility of generating disconnected graphs. References ---------- .. [1] I. Ispolatov, P. L. Krapivsky, A. Yuryev, "Duplication-divergence model of protein interaction network", Phys. Rev. E, 71, 061911, 2005. """ifp>1orp<0:msg=f"NetworkXError p={p} is not in [0,1]."raisenx.NetworkXError(msg)ifn<2:msg="n must be greater than or equal to 2"raisenx.NetworkXError(msg)G=nx.Graph()# Initialize the graph with two connected nodes.G.add_edge(0,1)i=2whilei<n:# Choose a random node from current graph to duplicate.random_node=seed.choice(list(G))# Make the replica.G.add_node(i)# flag indicates whether at least one edge is connected on the replica.flag=FalsefornbrinG.neighbors(random_node):ifseed.random()<p:# Link retention step.G.add_edge(i,nbr)flag=Trueifnotflag:# Delete replica if no edges retained.G.remove_node(i)else:# Successful duplication.i+=1returnG