Source code for easygraph.functions.path.average_shortest_path_length

import warnings

import easygraph as eg

from easygraph.functions.path.path import *


[docs]def average_shortest_path_length(G, weight=None, method=None): r"""Returns the average shortest path length. The average shortest path length is .. math:: a =\sum_{\substack{s,t \in V \\ s\neq t}} \frac{d(s, t)}{n(n-1)} where `V` is the set of nodes in `G`, `d(s, t)` is the shortest path from `s` to `t`, and `n` is the number of nodes in `G`. .. versionchanged:: 3.0 An exception is raised for directed graphs that are not strongly connected. Parameters ---------- G : EasyGraph graph weight : None, string or function, optional (default = None) If None, every edge has weight/distance/cost 1. If a string, use this edge attribute as the edge weight. Any edge attribute not present defaults to 1. If this is a function, the weight of an edge is the value returned by the function. The function must accept exactly three positional arguments: the two endpoints of an edge and the dictionary of edge attributes for that edge. The function must return a number. method : string, optional (default = 'unweighted' or 'dijkstra') The algorithm to use to compute the path lengths. Supported options are 'unweighted', 'dijkstra', 'bellman-ford', 'floyd-warshall' and 'floyd-warshall-numpy'. Other method values produce a ValueError. The default method is 'unweighted' if `weight` is None, otherwise the default method is 'dijkstra'. Raises ------ NetworkXPointlessConcept If `G` is the null graph (that is, the graph on zero nodes). NetworkXError If `G` is not connected (or not strongly connected, in the case of a directed graph). ValueError If `method` is not among the supported options. Examples -------- >>> G = eg.path_graph(5) >>> eg.average_shortest_path_length(G) 2.0 For disconnected graphs, you can compute the average shortest path length for each component >>> G = eg.Graph([(1, 2), (3, 4)]) >>> for C in (G.subgraph(c).copy() for c in eg.connected_components(G)): ... print(eg.average_shortest_path_length(C)) 1.0 1.0 """ single_source_methods = ["single_source_bfs", "Dijkstra"] all_pairs_methods = ["Floyed"] supported_methods = single_source_methods + all_pairs_methods if method is None: method = "single_source_bfs" if weight is None else "dijkstra" if method not in supported_methods: raise ValueError(f"method not supported: {method}") n = len(G) # For the special case of the null graph, raise an exception, since # there are no paths in the null graph. if n == 0: msg = ( "the null graph has no paths, thus there is no average shortest path length" ) raise eg.EasyGraphPointlessConcept(msg) # For the special case of the trivial graph, return zero immediately. if n == 1: return 0 # Shortest path length is undefined if the graph is not strongly connected. if G.is_directed() and not eg.is_strongly_connected(G): raise eg.EasyGraphError("Graph is not strongly connected.") # Shortest path length is undefined if the graph is not connected. if not G.is_directed() and not eg.is_connected(G): raise eg.EasyGraphError("Graph is not connected.") # Compute all-pairs shortest paths. def path_length(v): if method == "single_source_bfs": return eg.single_source_bfs(G, v) elif method == "dijkstra": return eg.Dijkstra(G, v, weight=weight) if method in single_source_methods: # Sum the distances for each (ordered) pair of source and target node. s = sum(l for u in G for l in path_length(u).values()) else: all_pairs = eg.Floyed(G, weight=weight) s = sum(sum(t.values()) for t in all_pairs.values()) return s / (n * (n - 1))