def GetTemporalClosenessInstantaneous(t, start_t=0, delta=1): """Calculates the temporal closeness values of all nodes for a given start time start_t in a temporal network t. This function returns a numpy array of (temporal) closeness centrality values. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param start_t: the start time for which to consider time-respecting paths (default 0). This is important, since any unambigious definition of a shortest time-respecting path between two nodes must include the time range to be considered (c.f. Holme and Saramäki, Phys. Rep., 2012) @param delta: the maximum time difference time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork. """ closeness = np.array([0.]*len(t.nodes)) # Calculate all shortest time-respecting paths D, paths = Paths.GetTemporalDistanceMatrix(t, start_t, delta, collect_paths=False) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap( t ) # Calculate closeness for each node u, by summing the reciprocal of its # distances to all other nodes. Note that this definition of closeness centrality # is required for directed networks that are not strongly connected. for u in t.nodes: for v in t.nodes: if u!=v: closeness[name_map[u]] += 1./D[name_map[v], name_map[u]] return closeness
def GetStaticEigenvectorCentrality(t, model='SECOND'): """Computes eigenvector centralities of nodes in the second-order aggregate network, and aggregates eigenvector centralities to obtain the eigenvector centrality of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value.""" if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") name_map = Utilities.firstOrderNameMap(t) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute eigenvector centrality in second-order network A = Utilities.getSparseAdjacencyMatrix(g2, attribute="weight", transposed=True) evcent_2 = Utilities.StationaryDistribution(A, False) # Aggregate to obtain first-order eigenvector centrality evcent_1 = np.zeros(len(name_map)) sep = t.separator for i in range(len(evcent_2)): # Get name of target node target = g2.vs()[i]["name"].split(sep)[1] evcent_1[name_map[target]] += np.real(evcent_2[i]) return np.real(evcent_1 / sum(evcent_1))
def GetStaticEigenvectorCentrality(t, model='SECOND'): """Computes eigenvector centralities of nodes in the second-order aggregate network, and aggregates eigenvector centralities to obtain the eigenvector centrality of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value.""" if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") name_map = Utilities.firstOrderNameMap(t) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute eigenvector centrality in second-order network A = Utilities.getSparseAdjacencyMatrix( g2, attribute="weight", transposed=True ) evcent_2 = Utilities.StationaryDistribution( A, False ) # Aggregate to obtain first-order eigenvector centrality evcent_1 = np.zeros(len(name_map)) sep = t.separator for i in range(len(evcent_2)): # Get name of target node target = g2.vs()[i]["name"].split(sep)[1] evcent_1[name_map[target]] += np.real(evcent_2[i]) return np.real(evcent_1/sum(evcent_1))
def GetTemporalBetweenness(t, delta=1, normalized=False): """Calculates the temporal betweenness centralities of all nodes in a temporal network t based on the shortest time-respecting paths with a maximum waiting time of delta. This function returns a numpy array of temporal betweenness centrality values of nodes. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param delta: the maximum time difference used in the time-respecting path definition (default 1). Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork @param normalized: whether or not to normalize centralities by dividing each value byt the total number of shortest time-respecting paths. """ bw = np.array([0] * len(t.nodes)) S = 0 name_map = Utilities.firstOrderNameMap(t) minD, minPaths = Paths.GetMinTemporalDistance(t, delta=1, collect_paths=True) for v in t.nodes: for w in t.nodes: for p in minPaths[v][w]: for i in range(1, len(p) - 1): bw[name_map[p[i][0]]] += 1 S += 1 return bw
def GetFirstOrderDistanceMatrix(t): """Calculates a matrix D containing the shortest path lengths between all pairs of nodes calculated based on the topology of the *first-order* aggregate network. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network to calculate shortest path lengths for based on a first-order aggregate representation """ # This way of generating the first-order time-aggregated network makes sure that # links are not omitted even if they do not contribute to any time-respecting path g1 = t.igraphFirstOrder(all_links=False, force=True) name_map = Utilities.firstOrderNameMap(t) D = np.zeros(shape=(len(t.nodes), len(t.nodes))) D.fill(np.inf) np.fill_diagonal(D, 0) for v in g1.vs()["name"]: for w in g1.vs()["name"]: # Compute all shortest paths using igraph X = g1.get_shortest_paths(v, w) for p in X: if len(p) > 0: D[name_map[v], name_map[w]] = len(p) - 1 return D
def GetStaticPageRank(t, model='SECOND'): """Computes PageRank of nodes based on the second-order aggregate network, and aggregates PageRank values to obtain the PageRank of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") name_map = Utilities.firstOrderNameMap( t ) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute betweenness centrality in second-order network pagerank_2 = np.array(g2.pagerank(weights=g2.es()['weight'], directed=True)) # Aggregate to obtain first-order eigenvector centrality pagerank_1 = np.zeros(len(name_map)) sep = t.separator for i in range(len(pagerank_2)): # Get name of target node target = g2.vs()[i]["name"].split(sep)[1] pagerank_1[name_map[target]] += pagerank_2[i] return pagerank_1/sum(pagerank_1)
def GetStaticCloseness(t, model='SECOND'): """Computes closeness centralities of nodes based on the first- or second-order time-aggregated network. @param t: The temporal network instance for which closeness centralities will be computed @param model: either C{"FIRST"}, C{"SECOND"} or C{"SECONDNULL"}, where C{"SECOND"} is the the default value. """ if model =='FIRST': D = Paths.GetFirstOrderDistanceMatrix(t) else: D = Paths.GetSecondOrderDistanceMatrix(t, model) name_map = Utilities.firstOrderNameMap( t ) closeness = np.zeros(len(name_map)) # Calculate closeness for each node u, by summing the reciprocal of its # distances to all other nodes. Note that this definition of closeness centrality # is required for directed networks that are not strongly connected. for u in t.nodes: for v in t.nodes: if u!=v: closeness[name_map[u]] += 1./D[name_map[v], name_map[u]] return closeness
def GetTemporalCloseness(t, delta=1): """Calculates the temporal closeness centralities of all nodes in a temporal network t, based on the minimal shortest time-respecting paths with a maximum time difference of delta. This function then returns a numpy array of average (temporal) closeness centrality values of nodes. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param delta: the maximum waiting time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork """ cl = np.array([0.]*len(t.nodes)) name_map = Utilities.firstOrderNameMap( t ) minD, minPaths = Paths.GetMinTemporalDistance(t, delta, collect_paths=False) for u in t.nodes: for v in t.nodes: if u!= v: cl[name_map[v]] += 1./minD[name_map[u], name_map[v]] return cl
def GetFirstOrderDistanceMatrix(t): """Calculates a matrix D containing the shortest path lengths between all pairs of nodes calculated based on the topology of the *first-order* aggregate network. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network to calculate shortest path lengths for based on a first-order aggregate representation """ # This way of generating the first-order time-aggregated network makes sure that # links are not omitted even if they do not contribute to any time-respecting path g1 = t.igraphFirstOrder(all_links=False, force=True) name_map = Utilities.firstOrderNameMap( t ) D = np.zeros(shape=(len(t.nodes),len(t.nodes))) D.fill(np.inf) np.fill_diagonal(D, 0) for v in g1.vs()["name"]: for w in g1.vs()["name"]: # Compute all shortest paths using igraph X = g1.get_shortest_paths(v,w) for p in X: if len(p)>0: D[name_map[v], name_map[w]] = len(p)-1 return D
def GetTemporalBetweenness(t, delta=1, normalized=False): """Calculates the temporal betweenness centralities of all nodes in a temporal network t based on the shortest time-respecting paths with a maximum waiting time of delta. This function returns a numpy array of temporal betweenness centrality values of nodes. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param delta: the maximum time difference used in the time-respecting path definition (default 1). Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork @param normalized: whether or not to normalize centralities by dividing each value byt the total number of shortest time-respecting paths. """ bw = np.array([0]*len(t.nodes)) S = 0 name_map = Utilities.firstOrderNameMap(t) minD, minPaths = Paths.GetMinTemporalDistance(t, delta=1, collect_paths=True) for v in t.nodes: for w in t.nodes: for p in minPaths[v][w]: for i in range(1,len(p)-1): bw[name_map[p[i][0]]] += 1 S+=1 return bw
def GetTemporalCloseness(t, delta=1): """Calculates the temporal closeness centralities of all nodes in a temporal network t, based on the minimal shortest time-respecting paths with a maximum time difference of delta. This function then returns a numpy array of average (temporal) closeness centrality values of nodes. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param delta: the maximum waiting time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork """ cl = np.array([0.] * len(t.nodes)) name_map = Utilities.firstOrderNameMap(t) minD, minPaths = Paths.GetMinTemporalDistance(t, delta, collect_paths=False) for u in t.nodes: for v in t.nodes: if u != v: cl[name_map[v]] += 1. / minD[name_map[u], name_map[v]] return cl
def GetStaticCloseness(t, model='SECOND'): """Computes closeness centralities of nodes based on the first- or second-order time-aggregated network. @param t: The temporal network instance for which closeness centralities will be computed @param model: either C{"FIRST"}, C{"SECOND"} or C{"SECONDNULL"}, where C{"SECOND"} is the the default value. """ if model == 'FIRST': D = Paths.GetFirstOrderDistanceMatrix(t) else: D = Paths.GetSecondOrderDistanceMatrix(t, model) name_map = Utilities.firstOrderNameMap(t) closeness = np.zeros(len(name_map)) # Calculate closeness for each node u, by summing the reciprocal of its # distances to all other nodes. Note that this definition of closeness centrality # is required for directed networks that are not strongly connected. for u in t.nodes: for v in t.nodes: if u != v: closeness[name_map[u]] += 1. / D[name_map[v], name_map[u]] return closeness
def GetTemporalBetweennessInstantaneous(t, start_t=0, delta=1, normalized=False): """Calculates the temporal betweennness values of all nodes fir a given start time start_t in an empirical temporal network t. This function returns a numpy array of (temporal) betweenness centrality values. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal betweenness centralities will be computed @param start_t: the start time for which to consider time-respecting paths (default 0). This is important, since any unambigious definition of a shortest time-respecting path between two nodes must include the time range to be considered (c.f. Holme and Saramäki, Phys. Rep., 2012) @param delta: the maximum waiting time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork @param normalized: whether or not to normalize the temporal betweenness centrality values by dividing by the number of all shortest time-respecting paths in the temporal network. """ bw = np.array([0] * len(t.nodes)) # First calculate all shortest time-respecting paths starting at time start_t D, paths = Paths.GetTemporalDistanceMatrix(t, start_t, delta, collect_paths=True) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap(t) # Compute betweenness scores of all nodes based on shortest time-respecting paths k = 0 for u in t.nodes: for v in t.nodes: if u != v: for p in paths[u][v]: for i in range(1, len(p) - 1): bw[name_map[p[i][0]]] += 1 k += 1 # Normalize by dividing by the total number of shortest time-respecting paths if normalized: bw = bw / k return bw
def GetStaticPageRank(t, model='SECOND', projection='TARGET', normalization=False): """Computes PageRank of nodes based on the second-order aggregate network, and aggregates PageRank values to obtain the PageRank of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ assert model is "SECOND" or model is "NULL" assert projection is 'TARGET' or projection is 'SOURCE' name_map = Utilities.firstOrderNameMap(t) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute pagerank centrality in second-order network pagerank_2 = np.array(g2.pagerank(weights=g2.es()['weight'], directed=True)) # Aggregate to obtain first-order pagerank centrality pagerank_1 = np.zeros(len(name_map)) counts = np.array([1] * len(name_map)) sep = t.separator for i in range(len(pagerank_2)): # Get name of target node if projection == 'TARGET': target = g2.vs()[i]["name"].split(sep)[1] pagerank_1[name_map[target]] += pagerank_2[i] counts[name_map[target]] += 1 else: source = g2.vs()[i]["name"].split(sep)[0] pagerank_1[name_map[source]] += pagerank_2[i] counts[name_map[source]] += 1 if normalization == True: pagerank_1 = pagerank_1 / counts return pagerank_1
def GetMinTemporalDistance(t, delta=1, collect_paths=True): """ Computes the minimum temporal distance between all pairs of nodes in terms of time-respecting paths (using a given maximum time difference delta), across all possible starting times in the temporal network @param t: the temporal network to calculate the distance for @param delta: the maximum waiting time to be used for the definition of time-respecting paths. Note that this is independent of the delta parameter set in the temporal networks instancd for the two-path extraction @param collect_paths: whether or not to return all shortest time-respecting paths. If False, only shortest path distances will be returned. """ Log.add('Computing minimum temporal distances for delta = ' + str(int(delta)) + ' ...') name_map = Utilities.firstOrderNameMap(t) minD = np.zeros(shape=(len(t.nodes), len(t.nodes))) minD.fill(np.inf) # Each node is connected to itself via a path of length zero np.fill_diagonal(minD, 0) minPaths = defaultdict(lambda: defaultdict(lambda: [])) for start_t in t.ordered_times: D, paths = GetTemporalDistanceMatrix(t, start_t, delta, collect_paths) for v in t.nodes: for w in t.nodes: if D[name_map[v], name_map[w]] < minD[name_map[v], name_map[w]]: minD[name_map[v], name_map[w]] = D[name_map[v], name_map[w]] minPaths[v][w] = paths[v][w] elif D[name_map[v], name_map[w]] == minD[name_map[v], name_map[w]] and minD[ name_map[v], name_map[w]] < np.inf: for p in paths[v][w]: if p not in minPaths[v][w]: minPaths[v][w] = minPaths[v][w] + [p] Log.add('finished.') return minD, minPaths
def GetStaticPageRank(t, model='SECOND', projection='TARGET', normalization=False): """Computes PageRank of nodes based on the second-order aggregate network, and aggregates PageRank values to obtain the PageRank of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ assert model is "SECOND" or model is "NULL" assert projection is 'TARGET' or projection is 'SOURCE' name_map = Utilities.firstOrderNameMap( t ) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute pagerank centrality in second-order network pagerank_2 = np.array(g2.pagerank(weights=g2.es()['weight'], directed=True)) # Aggregate to obtain first-order pagerank centrality pagerank_1 = np.zeros(len(name_map)) counts = np.array([1]*len(name_map)) sep = t.separator for i in range(len(pagerank_2)): # Get name of target node if projection == 'TARGET': target = g2.vs()[i]["name"].split(sep)[1] pagerank_1[name_map[target]] += pagerank_2[i] counts[name_map[target]] +=1 else: source = g2.vs()[i]["name"].split(sep)[0] pagerank_1[name_map[source]] += pagerank_2[i] counts[name_map[source]] +=1 if normalization == True: pagerank_1 = pagerank_1 / counts return pagerank_1
def GetTemporalBetweennessInstantaneous(t, start_t=0, delta=1, normalized=False): """Calculates the temporal betweennness values of all nodes fir a given start time start_t in an empirical temporal network t. This function returns a numpy array of (temporal) betweenness centrality values. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal betweenness centralities will be computed @param start_t: the start time for which to consider time-respecting paths (default 0). This is important, since any unambigious definition of a shortest time-respecting path between two nodes must include the time range to be considered (c.f. Holme and Saramäki, Phys. Rep., 2012) @param delta: the maximum waiting time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork @param normalized: whether or not to normalize the temporal betweenness centrality values by dividing by the number of all shortest time-respecting paths in the temporal network. """ bw = np.array([0]*len(t.nodes)) # First calculate all shortest time-respecting paths starting at time start_t D, paths = Paths.GetTemporalDistanceMatrix(t, start_t, delta, collect_paths=True) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap( t ) # Compute betweenness scores of all nodes based on shortest time-respecting paths k=0 for u in t.nodes: for v in t.nodes: if u != v: for p in paths[u][v]: for i in range(1, len(p)-1): bw[name_map[p[i][0]]] += 1 k+=1 # Normalize by dividing by the total number of shortest time-respecting paths if normalized: bw = bw/k return bw
def GetSecondOrderDistanceMatrix(t, model='SECOND'): """Calculates a matrix D containing the shortest path lengths between all pairs of nodes calculated based on the topology of the *second-order* aggregate network. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network to calculate shortest path lengths for based on a second-order aggregate representation @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") name_map = Utilities.firstOrderNameMap(t) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() D = np.zeros(shape=(len(t.nodes), len(t.nodes))) D.fill(np.inf) np.fill_diagonal(D, 0) sep = t.separator for v in g2.vs()["name"]: source = v.split(sep)[0] for w in g2.vs()["name"]: target = w.split(sep)[1] X = g2.get_shortest_paths(v, w) for p in X: if len(p) > 0: D[name_map[source], name_map[target]] = min( len(p), D[name_map[source], name_map[target]]) return D
def GetMinTemporalDistance(t, delta=1, collect_paths=True): """ Computes the minimum temporal distance between all pairs of nodes in terms of time-respecting paths (using a given maximum time difference delta), across all possible starting times in the temporal network @param t: the temporal network to calculate the distance for @param delta: the maximum waiting time to be used for the definition of time-respecting paths. Note that this is independent of the delta parameter set in the temporal networks instancd for the two-path extraction @param collect_paths: whether or not to return all shortest time-respecting paths. If False, only shortest path distances will be returned. """ Log.add('Computing minimum temporal distances for delta = ' + str(int(delta)) + ' ...') name_map = Utilities.firstOrderNameMap( t ) minD = np.zeros(shape=(len(t.nodes),len(t.nodes))) minD.fill(np.inf) # Each node is connected to itself via a path of length zero np.fill_diagonal(minD, 0) minPaths = defaultdict( lambda: defaultdict( lambda: [] ) ) for start_t in t.ordered_times: D, paths = GetTemporalDistanceMatrix(t, start_t, delta, collect_paths) for v in t.nodes: for w in t.nodes: if D[name_map[v], name_map[w]] < minD[name_map[v], name_map[w]]: minD[name_map[v], name_map[w]] = D[name_map[v], name_map[w]] minPaths[v][w] = paths[v][w] elif D[name_map[v], name_map[w]] == minD[name_map[v], name_map[w]] and minD[name_map[v], name_map[w]] < np.inf: for p in paths[v][w]: if p not in minPaths[v][w]: minPaths[v][w] = minPaths[v][w] + [p] Log.add('finished.') return minD, minPaths
def GetSecondOrderDistanceMatrix(t, model='SECOND'): """Calculates a matrix D containing the shortest path lengths between all pairs of nodes calculated based on the topology of the *second-order* aggregate network. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network to calculate shortest path lengths for based on a second-order aggregate representation @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") name_map = Utilities.firstOrderNameMap( t ) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() D = np.zeros(shape=(len(t.nodes),len(t.nodes))) D.fill(np.inf) np.fill_diagonal(D, 0) sep = t.separator for v in g2.vs()["name"]: source = v.split(sep)[0] for w in g2.vs()["name"]: target = w.split(sep)[1] X = g2.get_shortest_paths(v,w) for p in X: if len(p)>0: D[name_map[source], name_map[target]] = min(len(p), D[name_map[source], name_map[target]]) return D
def GetTemporalClosenessInstantaneous(t, start_t=0, delta=1): """Calculates the temporal closeness values of all nodes for a given start time start_t in a temporal network t. This function returns a numpy array of (temporal) closeness centrality values. The ordering of these values corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between node names and array indices can be found in Utilities.firstOrderNameMap(). @param t: the temporal network for which temporal closeness centralities will be computed @param start_t: the start time for which to consider time-respecting paths (default 0). This is important, since any unambigious definition of a shortest time-respecting path between two nodes must include the time range to be considered (c.f. Holme and Saramäki, Phys. Rep., 2012) @param delta: the maximum time difference time used in the time-respecting path definition (default 1) Note that this parameter is independent from the delta used internally for the extraction of two-paths by the class TemporalNetwork. """ closeness = np.array([0.] * len(t.nodes)) # Calculate all shortest time-respecting paths D, paths = Paths.GetTemporalDistanceMatrix(t, start_t, delta, collect_paths=False) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap(t) # Calculate closeness for each node u, by summing the reciprocal of its # distances to all other nodes. Note that this definition of closeness centrality # is required for directed networks that are not strongly connected. for u in t.nodes: for v in t.nodes: if u != v: closeness[name_map[u]] += 1. / D[name_map[v], name_map[u]] return closeness
def GetStaticBetweenness(t, model='SECOND'): """Computes betweenness centralities of nodes based on the second-order aggregate network, and aggregates betweenness centralities to obtain the betweenness centrality of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") D = Paths.GetSecondOrderDistanceMatrix(t) name_map = Utilities.firstOrderNameMap( t ) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute betweenness centrality based on second-order network bwcent_1 = np.zeros(len(name_map)) sep = t.separator for v in g2.vs()["name"]: for w in g2.vs()["name"]: s = v.split(sep)[0] t = w.split(sep)[1] X = g2.get_all_shortest_paths(v,w) for p in X: if D[name_map[s], name_map[t]] == len(p) and len(p) > 1: for i in range(len(p)): source = g2.vs()["name"][p[i]].split(sep)[0] if i>0: bwcent_1[name_map[source]] += 1 return bwcent_1
def GetStaticBetweenness(t, model='SECOND'): """Computes betweenness centralities of nodes based on the second-order aggregate network, and aggregates betweenness centralities to obtain the betweenness centrality of nodes in the first-order network. @param t: The temporalnetwork instance to work on @param model: either C{"SECOND"} or C{"NULL"}, where C{"SECOND"} is the the default value. """ if (model is "SECOND" or "NULL") == False: raise ValueError("model must be one of \"SECOND\" or \"NULL\"") D = Paths.GetSecondOrderDistanceMatrix(t) name_map = Utilities.firstOrderNameMap(t) if model == 'SECOND': g2 = t.igraphSecondOrder() else: g2 = t.igraphSecondOrderNull() # Compute betweenness centrality based on second-order network bwcent_1 = np.zeros(len(name_map)) sep = t.separator for v in g2.vs()["name"]: for w in g2.vs()["name"]: s = v.split(sep)[0] t = w.split(sep)[1] X = g2.get_all_shortest_paths(v, w) for p in X: if D[name_map[s], name_map[t]] == len(p) and len(p) > 1: for i in range(len(p)): source = g2.vs()["name"][p[i]].split(sep)[0] if i > 0: bwcent_1[name_map[source]] += 1 return bwcent_1
def GetTemporalDistanceMatrix(t, start_t=-1, delta=1, collect_paths=True): """A new and faster method to compute the (topologically) shortest time-respecting paths between all pairs of nodes starting at time start_t in an empirical temporal network t. This function returns a tuple consisting of 1) a matrix D containing the shortest time-respecting path lengths between all pairs of nodes. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). 2) a list of shortest time-respecting paths, each entry being an ordered sequence of nodes on the corresponding path. @param t: the temporal network to calculate shortest time-respecting paths for @param start_t: the start time for which to consider time-respecting paths (default is t.ordered_times[0]) @param delta: the maximum time difference to be used in the time-respecting path definition (default 1). Note that this parameter is independent from the internal parameter delta used for two-path extraction in the class TemporalNetwork @param collect_paths: whether or not to collect all shortest time-respecting paths (default = True). If this is set to False, the method will only compute the lengths of shortest time-respecting paths, but not return the actual paths. """ if start_t == -1: start_t = t.ordered_times[0] # Initialize dictionary taking shortest paths Paths = defaultdict(lambda: defaultdict(lambda: [])) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap(t) # Initialize topological distance matrix # TODO: This may yield a memory problem for large graphs D = np.zeros(shape=(len(t.nodes), len(t.nodes))) D.fill(np.inf) # For each node v, calculate shortest/fastest paths to all other nodes ... for v in t.nodes: # Mark node v as visited at the start time start_t... D[name_map[v], name_map[v]] = 0 Paths[v][v] = [[(v, start_t)]] stack = set([(v, start_t)]) # While there are nodes, which could possibly continue a time-respecting path while len(stack) > 0: (x, ts) = stack.pop() # Get indices of time range within which a time-respecting path via x # can possibly be continued min_ix = bisect_left(t.activities[x], ts) max_ix = bisect_left(t.activities[x], ts + delta) - 1 # For all time-stamps at which x is a source node ... for j in range(min_ix, max_ix + 1): time = t.activities[x][j] # For all edges starting at node x at this time for e in t.sources[time][x]: # We found a new node on a time-respecting path new_node = (e[1], time + 1) # This node can again continue time-respecting paths # The set will take care that no duplicates are recorded stack.add(new_node) # Check whether we found a time-respecting path shorter than the current shortest one ... if D[name_map[v], name_map[e[1]]] > D[name_map[v], name_map[e[0]]] + 1: # In this case we update the distance matrix D[name_map[v], name_map[e[1]]] = D[name_map[v], name_map[e[0]]] + 1 if collect_paths == True: # Delete any previous shortest paths Paths[v][e[1]] = [] # Collect all paths to e[0] and concatenate with the current node e[1] for p in Paths[v][e[0]]: Paths[v][e[1]] = Paths[v][e[1]] + [ p + [(e[1], time + 1)] ] # We may also have found a path that has the same length as other shortest paths ... elif collect_paths == True and D[name_map[v], name_map[ e[1]]] == D[name_map[v], name_map[e[0]]] + 1: # Collect all paths to e[0] and concatenate with the current node e[1] for p in Paths[v][e[0]]: Paths[v][e[1]] = Paths[v][e[1]] + [ p + [(e[1], time + 1)] ] # The algorithm terminates as soon as it is impossible to continue any of the time-respecting paths return D, Paths
def GetTemporalDistanceMatrix(t, start_t=-1, delta=1, collect_paths=True): """A new and faster method to compute the (topologically) shortest time-respecting paths between all pairs of nodes starting at time start_t in an empirical temporal network t. This function returns a tuple consisting of 1) a matrix D containing the shortest time-respecting path lengths between all pairs of nodes. The ordering of rows/columns corresponds to the ordering of nodes in the vertex sequence of the igraph first order time-aggregated network. A mapping between nodes and indices can be found in Utilities.firstOrderNameMap(). 2) a list of shortest time-respecting paths, each entry being an ordered sequence of nodes on the corresponding path. @param t: the temporal network to calculate shortest time-respecting paths for @param start_t: the start time for which to consider time-respecting paths (default is t.ordered_times[0]) @param delta: the maximum time difference to be used in the time-respecting path definition (default 1). Note that this parameter is independent from the internal parameter delta used for two-path extraction in the class TemporalNetwork @param collect_paths: whether or not to collect all shortest time-respecting paths (default = True). If this is set to False, the method will only compute the lengths of shortest time-respecting paths, but not return the actual paths. """ if start_t == -1: start_t = t.ordered_times[0] # Initialize dictionary taking shortest paths Paths = defaultdict( lambda: defaultdict( lambda: [] ) ) # Get a mapping between node names and matrix indices name_map = Utilities.firstOrderNameMap( t ) # Initialize topological distance matrix # TODO: This may yield a memory problem for large graphs D = np.zeros(shape=(len(t.nodes),len(t.nodes))) D.fill(np.inf) # For each node v, calculate shortest/fastest paths to all other nodes ... for v in t.nodes: # Mark node v as visited at the start time start_t... D[name_map[v], name_map[v]] = 0 Paths[v][v] = [ [(v,start_t)] ] stack = set([ (v, start_t) ]) # While there are nodes, which could possibly continue a time-respecting path while len(stack)>0: (x,ts) = stack.pop() # Get indices of time range within which a time-respecting path via x # can possibly be continued min_ix = bisect_left(t.activities[x], ts) max_ix = bisect_left(t.activities[x], ts+delta)-1 # For all time-stamps at which x is a source node ... for j in range(min_ix, max_ix+1): time = t.activities[x][j] # For all edges starting at node x at this time for e in t.sources[time][x]: # We found a new node on a time-respecting path new_node = (e[1], time+1) # This node can again continue time-respecting paths # The set will take care that no duplicates are recorded stack.add( new_node ) # Check whether we found a time-respecting path shorter than the current shortest one ... if D[name_map[v], name_map[e[1]]] > D[name_map[v], name_map[e[0]]] + 1: # In this case we update the distance matrix D[name_map[v], name_map[e[1]]] = D[name_map[v], name_map[e[0]]] + 1 if collect_paths == True: # Delete any previous shortest paths Paths[v][e[1]] = [] # Collect all paths to e[0] and concatenate with the current node e[1] for p in Paths[v][e[0]]: Paths[v][e[1]] = Paths[v][e[1]] + [p + [(e[1],time+1)]] # We may also have found a path that has the same length as other shortest paths ... elif collect_paths == True and D[name_map[v], name_map[e[1]]] == D[name_map[v], name_map[e[0]]] + 1: # Collect all paths to e[0] and concatenate with the current node e[1] for p in Paths[v][e[0]]: Paths[v][e[1]] = Paths[v][e[1]] + [p + [(e[1],time+1)]] # The algorithm terminates as soon as it is impossible to continue any of the time-respecting paths return D, Paths