我试图模拟一个加权的、定向的、无标度的网络,如本文第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