def Molloy_Reed(degrees: Union[np.array, Dict[int, float]], multiedge: bool = False, relax: bool=False, node_uids: Optional[list] = None) -> Optional[Network]: """Generate Molloy-Reed graph. Generates a random undirected network with given degree sequence based on the Molloy-Reed algorithm. .. note:: The condition proposed by Erdös and Gallai (1967) is used to test whether the degree sequence is graphic, i.e. whether a network with the given degree sequence exists. Parameters ---------- degrees : list List of integer node degrees. The number of nodes of the generated network corresponds to len(degrees). relax : bool If True, we conceptually allow self-loops and multi-edges, but do not add them to the network This implies that the generated network may not have exactly sum(degrees)/2 links, but it ensures that the algorithm always finishes. node_uids : list Optional list of node uids that will be used. Examples -------- Generate random undirected network with given degree sequence >>> import pathpy as pp >>> random_network = pp.algorithms.random_graphs.Molloy_Reed([1,0]) >>> print(random_network.summary()) ... Network generation fails for non-graphic sequences >>> import pathpy as pp >>> random_network = pp.algorithms.random_graphs.Molloy_Reed([1,0]) >>> print(random_network) None """ # assume that we are given a graphical degree sequence if not is_graphic_Erdos_Gallai(degrees): return None # create empty network with n nodes n = len(degrees) network = Network(directed=False, multiedges=multiedge) if node_uids is None or len(node_uids) != n: LOG.info('No valid node uids given, generating numeric node uids') node_uids = [] for i in range(n): node_uids.append(str(i)) for i in range(n): network.add_node(node_uids[i]) # generate link stubs based on degree sequence stubs = [] for i in range(n): for _ in range(int(degrees[i])): stubs.append(str(node_uids[i])) # connect randomly chosen pairs of link stubs while(len(stubs) > 0): v, w = np.random.choice(stubs, 2, replace=False) if v == w or (multiedge == False and relax == False and network.nodes[w] in network.successors[v]): # remove random edge and add stubs if network.number_of_edges()>0: edge = random.choice(list(network.edges)) stubs.append(edge.v.uid) stubs.append(edge.w.uid) network.remove_edge(edge) else: if not network.nodes[w] in network.successors[v]: network.add_edge(v, w) stubs.remove(v) stubs.remove(w) return network
def Watts_Strogatz(n: int, s: int, p: float = 0.0, loops: bool = False, node_uids: Optional[list] = None) -> Network: """Undirected Watts-Strogatz lattice network Generates an undirected Watts-Strogatz lattice network with lattice dimensionality one. Parameters ---------- n : int The number of nodes in the generated network s : float The number of nearest neighbors that will be connected in the ring lattice p : float The rewiring probability node_uids : list Optional list of node uids that will be used. Examples -------- Generate a Watts-Strogatz network with 100 nodes >>> import pathpy as pp >>> small_world = pp.algorithms.random_graphs.Watts_Strogatz(n=100, s=2, p=0.1) >>> print(small_world.summary()) ... """ network = Network(directed=False) if node_uids is None or len(node_uids) != n: LOG.info('No valid node uids given, generating numeric node uids') node_uids = [] for i in range(n): network.add_node(Node(str(i))) node_uids.append(str(i)) else: for i in range(n): network.add_node(node_uids[i]) # construct a ring lattice (dimension 1) for i in range(n): if loops: x = 0 y = s else: x = 1 y = s+1 for j in range(x, y): v = network.nodes[node_uids[i]] w = network.nodes[node_uids[(i+j) % n]] if (v.uid, w.uid) not in network.edges: network.add_edge(v, w) if p == 0: # nothing to do here return network # Rewire each link with probability p for edge in tqdm(list(network.edges.values()), 'generating WS network'): if np.random.rand() < p: # Delete original link and remember source node v = edge.v.uid network.remove_edge(edge) # Find new random tgt, which is not yet connected to src new_target = None # This loop repeatedly chooses a random target until we find # a target not yet connected to src. Note that this could potentially # result in an infinite loop depending on parameters. while new_target is None: x = node_uids[np.random.randint(n)] if (x != v or loops) and (v, x) not in network.edges: new_target = x network.add_edge(v, new_target) return network