我试图模拟一个加权的、定向的、无标度的网络,如本文第3节所述。由于没有LaTeX排版,我尝试在下图中总结我对该过程的理解:
 
请记住,这是我对所述程序的解释,因此我理解中的错误可能是错误的根源。到目前为止,我尝试的解决方案并没有导致幂律度分布。我的代码如下:
import numpy as np
import networkx as nx
N = 1000   # Final no. of nodes
d = 80     # Parameter for edge-weight update (called delta in paper)
m0 = 10    # Initial nodes
w0 = 100   # Initial weights
m1_in  = 1 # Number of new edges pointing TOWARDS the new node
m1_out = 1 # Number of new edges pointing AWAY from the new node
m2 = 0     # Number of new edges between previously existing nodes
# Create fully connected networks
G = nx.complete_graph(n=m0, create_using=nx.DiGraph)
# Set initial weights equal to w0
for e in G.edges():
    G[e[0]][e[1]]['Transaction'] = w0
# At each timestep t
t = m0 #0
while t <= N:
    
    # Calculate in/out strength of existing nodes
    s_in  = dict(G.in_degree(weight='Transaction'))
    s_out = dict(G.out_degree(weight='Transaction'))
    
    # Calculate totals
    s_in_sum  = sum(s_in.values(), 0.0)
    s_out_sum = sum(s_out.values(), 0.0)
    
    # Probability of linking joining new edges to existing nodes
    p_in  = {k: v / s_in_sum for k, v in s_in.items()}
    p_out = {k: v / s_out_sum for k, v in s_out.items()}
    
    # ----------------------------------------------------------
    # Prob. of existing node RECEIVING new edge is given by in_limit
    # In-limit
    in_list  = [i for i in p_in.values()]     # Stores in-probabilities as a list
    in_limit = [0.0]                          # Initializes value at 0
    for i, p_i in enumerate(in_list):
        in_limit.append(p_i + in_limit[i])
    
    # Select m1_out existing nodes that will RECEIVE new edges
    in_neigh = select_neigh(lim_list=in_limit, num_neigh=m1_out)
    
    # CALL WEIGHT UPDATE
    # Before adding new neighbour, update strength of existing neighbours
    # After updating, add link (weight w0) to new node. New node is SOURCE of edge
    update_weights(G=G, neighbours=in_neigh, delta=d, s_dict=s_in, case_1a=False, case_1b=True)
    
    # ----------------------------------------------------------
    # Prob. of existing node being the SOURCE of a new edge is given by out_limit
    # Out-limit
    out_list  = [i for i in p_out.values()]   # Stores out-probabilities as a list
    out_limit = [0.0]                         # Initializes value at 0
    for i, p_o in enumerate(out_list):
        out_limit.append(p_o + out_limit[i])
    
    # CALL SELECT OUT-NEIGHBOUR
    # Select m1_in existing nodes that will be SOURCES of new edges
    out_neigh = select_neigh(lim_list=out_limit, num_neigh=m1_in)
    
    # CALL WEIGHT UPDATE
    # Before adding new neighbour, update strength of existing neighbours
    # After updating, add link (weight w0) to new node. New node is DESTINATION of edge
    update_weights(G=G, neighbours=out_neigh, delta=d, s_dict=s_out, case_1a=True, case_1b=False)
    
    # -----------------------------------------------------------
    # Add new node - new node is DESTINATION of new edge
    G.add_node(t)
    # Add paths to selected nodes
    for n in in_neigh:
        G.add_edge(n, t, Transaction=w0)
    
    # Add new node - new node is SOURCE of new edge
    for n in out_neigh:
        G.add_edge(t, n, Transaction=w0)
    
    # Case 2 - New edges appear between previously existing nodes
    # To do
    
    # Next step
    t += 1
我定义的功能如下:
# Select neighbours
def select_neigh(lim_list, num_neigh):
    '''
    Args
    ------------------------------------
    lim_list: list - Probability range for each node
    num_neigh: int - Number of incoming nodes to assign to the new node.
                     m1_out in the paper for INCOMING edges to a new node
                     m1_in in the paper for OUTGOING edges to a new node
    ------------------------------------
    Returns: list of nodes selected for the new edge
    '''
    
    # List to store the neighbours
    neighbours = []
    
    # Flag to see if node is already a neighbour
    already_neighbour = False
    
    # Iterate through EXISTING NODES
    i = 0
    while i < num_neigh:
        rnd = np.random.random() # random number between 0 and 1
        # compare the random number to the limits and add node accordingly
        for j in range(len(lim_list) - 1):
            if rnd >= lim_list[j] and rnd < lim_list[j+1]:
                # if j is already a neighbor
                if j in neighbours:
                    # Raise the flag
                    already_neighbour =True
                else:
                    # if j is not already a neighbor add it to the neighbors list
                    neighbours.append(j)    
        # if the alread_neighbor flag is true, decrement i to redo the choice randomly and reset flag               
        if already_neighbour == True:
            already_neighbour = False
            i -= 1 # To repeat the choice of the node
        i+=1
    
    # Return result
    return neighbours
# Update weights
def update_weights(G, neighbours, delta, s_dict, case_1a = False, case_1b=False):
    '''
    Args
    ------------------------------------
    G: nx.DiGraph object - NetworkX network before being updated
    neighbours: list - list of neighbours to generate links into/from
    delta: float - delta parameter in the paper. Updates weights
    s_dict: Strength dictionary of every node.
            In/Out depends on incoming/outgoing edges
    case_1a: bool - Flag that determines if new edges are INCOMING towards existing nodes
    case_1b: bool - Flag that determines if new edges are OUTGOING from existing nodes
    '''
    if case_1b:
        # Update weights of existing edges
        for n in neighbours:
            for e in G.in_edges(n, data=True):
                w_in = G[e[0]][n]['Transaction'] # Value of edges incoming to n
                d_w = (delta*w_in)/s_dict[e[0]]  # Value of shift
                # Update weight
                G[e[0]][n]['Transaction'] += d_w
    
    if case_1a:
        # Update weights of existing edges
        for n in neighbours:
            for e in G.out_edges(n, data=True):
                w_nj = G[n][e[1]]['Transaction'] # Value of edges incoming to n
                d_w = (delta*w_nj)/s_dict[e[1]]  # Value of shift
                # Update weight
                G[n][e[1]]['Transaction'] += d_w