Source code for dynamicalab.generators.kernel


import networkx as nx
import numpy as np
import random as rdm


[docs]def generalized_PA_model(nu, p, N, directed=False, max_step=1e4): """Generates a network using the generalized preferential attachment model. The process goes as follows: 1. Initialize the network with two connected nodes. 2. Choose a birth event with probability ``p``, or a growing event with probability ``1-p``. Then: a. If a birth event, choose and place a new node in the network. b. If a growth event, choose an existing node proportionnal to its total degree powers ``nu``. 3. Choose an existing node following 2b. 4. Connect the node from step 2 with node from step 3. 5. Repeat steps 2,3,4 until the number ``N`` is reached. **Parameters** nu : float Kernel power. p : float Birth probability. N : int Number of nodes. The estimated steps to reach ``N`` nodes is ``N/p``. directed : bool : (default=False) Construct a directed network. If true, new edges are connected toward older nodes and the output is a ``nx.Digraph`` max_step : int : (default=1e4) Maximum number of events before the algorithm ends. This does not apply if the desired number of nodes is reached. **Returns** nx.Digraph or nx.Graph The resulting graph. **Raise** ``ValueError``  Occurs if the birth probability ``p`` is smaller or equal to zero. **Example** .. code:: python import dynamicalab as dlb nu = 1.0 p = 1.0 N = 40 G = dlb.generalized_PA_model(nu, p, N) .. note:: See `Young et al., 2018 <https://arxiv.org/pdf/1803.09191.pdf>`_ for an intensive description of the model. .. image:: /_static/assets/zoo.png :align: center Example of networks for ``p=1``. Figure inspired of `Young et al., 2018 <https://arxiv.org/pdf/1803.09191.pdf>`_. """ def add_edge(nodeA, nodeB, G, k, directed): k[nodeA] += 1 k[nodeB] += 1 G.add_edge(nodeA, nodeB) if directed: G.add_edge(nodeB, nodeA) def choose_existing_node(degrees, nu, tot_k): k_ch = rdm.random()*tot_k for i, k in enumerate(degrees): if k_ch-(k**nu)<=0.0: return i else: k_ch -= (k**nu) if p<=0: raise ValueError("p must be larger than 0. ") degrees = [0]*N G = nx.DiGraph() if directed else nx.Graph() # Step 1. Initiate the network add_edge(0, 1, G, degrees, directed) n_nodes = 2 nodeB, nodeA = 0, 0 for t in range(int(max_step)): tot_k = np.sum([k**nu for k in degrees[:n_nodes]]) if rdm.random()<p: nodeA = n_nodes n_nodes += 1 else: nodeA = choose_existing_node(degrees, nu, tot_k) nodeB = choose_existing_node(degrees, nu, tot_k) add_edge(nodeA, nodeB, G, degrees, directed) if (n_nodes>=N): return G raise RuntimeWarning("Maximum number of steps reached") return G