def __ranking_metrics_heuristic(topology, od_pairs=None): """ Sort OD pairs of a topology according to the Ranking Metrics Heuristics method Parameters ---------- topology : Topology or DirectedTopology The topology od_pairs : list, optional The OD pairs to be ranked (must be a subset of the OD pairs of the topology). If None, then the heuristic is calculated for all the OD pairs of the topology Returns ------- od_pairs : list The sorted list of OD pairs """ # Ranking Metrics Heuristic if od_pairs is None: od_pairs = od_pairs_from_topology(topology) fan_in, fan_out = fan_in_out_capacities(topology) degree = topology.degree() min_capacity = {(u, v): min(fan_out[u], fan_in[v]) for u, v in od_pairs} min_degree = {(u, v): min(degree[u], degree[v]) for u, v in od_pairs} # NFUR calculation is expensive, so before calculating it, the code # checks if it is really needed, i.e. if there are ties after capacity # and degree sorting cap_deg_pairs = [(min_capacity[(u, v)], min_degree[(u, v)]) for u, v in od_pairs] nfur_required = any((val > 1 for val in Counter(cap_deg_pairs).values())) if not nfur_required: # Sort all OD_pairs return sorted(od_pairs, key=lambda od_pair: (min_capacity[od_pair], min_degree[od_pair])) # if NFUR is required we calculate it. If fast is True, this function # returns the betweenness centrality rather than the NFUR. # Use betweenness centrality instead of NFUR if the topology is not trivial # for scalability reasons. # The threshold of 300 is a conservative value which allows fast execution # on most machines. parallelize = (topology.number_of_edges() > 100) fast = (topology.number_of_edges() > 300) nfur = __calc_nfur(topology, fast, parallelize) # Note: here we use the opposite of max rather than the inverse of max # (which is the formulation of the paper) because we only need to rank # in reverse order the max of NFURs. Since all NFURs are >=0, # using the opposite yields the same results as the inverse, but there # is no risk of incurring in divisions by 0. max_inv_nfur = {(u, v): -max(nfur[u], nfur[v]) for u, v in od_pairs} # Sort all OD_pairs return sorted( od_pairs, key=lambda od_pair: (min_capacity[od_pair], min_degree[od_pair], max_inv_nfur[od_pair]))
def __ranking_metrics_heuristic(topology, od_pairs=None): """ Sort OD pairs of a topology according to the Ranking Metrics Heuristics method Parameters ---------- topology : Topology or DirectedTopology The topology od_pairs : list, optional The OD pairs to be ranked (must be a subset of the OD pairs of the topology). If None, then the heuristic is calculated for all the OD pairs of the topology Returns ------- od_pairs : list The sorted list of OD pairs """ # Ranking Metrics Heuristic if od_pairs is None: od_pairs = od_pairs_from_topology(topology) fan_in, fan_out = fan_in_out_capacities(topology) degree = topology.degree() min_capacity = {(u, v): min(fan_out[u], fan_in[v]) for u, v in od_pairs} min_degree = {(u, v): min(degree[u], degree[v]) for u, v in od_pairs} # NFUR calculation is expensive, so before calculating it, the code # checks if it is really needed, i.e. if there are ties after capacity # and degree sorting cap_deg_pairs = [(min_capacity[(u, v)], min_degree[(u, v)]) for u, v in od_pairs] nfur_required = any((val > 1 for val in Counter(cap_deg_pairs).values())) if not nfur_required: # Sort all OD_pairs return sorted(od_pairs, key=lambda od_pair: (min_capacity[od_pair], min_degree[od_pair])) # if NFUR is required we calculate it. If fast is True, this function # returns the betweenness centrality rather than the NFUR. # Use betweenness centrality instead of NFUR if the topology is not trivial # for scalability reasons. # The threshold of 300 is a conservative value which allows fast execution # on most machines. parallelize = (topology.number_of_edges() > 100) fast = (topology.number_of_edges() > 300) nfur = __calc_nfur(topology, fast, parallelize) # Note: here we use the opposite of max rather than the inverse of max # (which is the formulation of the paper) because we only need to rank # in reverse order the max of NFURs. Since all NFURs are >=0, # using the opposite yields the same results as the inverse, but there # is no risk of incurring in divisions by 0. max_inv_nfur = {(u, v):-max(nfur[u], nfur[v]) for u, v in od_pairs} # Sort all OD_pairs return sorted(od_pairs, key=lambda od_pair: (min_capacity[od_pair], min_degree[od_pair], max_inv_nfur[od_pair]))