|
"""Functions related to the Wiener Index of a graph. |
|
|
|
The Wiener Index is a topological measure of a graph |
|
related to the distance between nodes and their degree. |
|
The Schultz Index and Gutman Index are similar measures. |
|
They are used categorize molecules via the network of |
|
atoms connected by chemical bonds. The indices are |
|
correlated with functional aspects of the molecules. |
|
|
|
References |
|
---------- |
|
.. [1] `Wikipedia: Wiener Index <https://en.wikipedia.org/wiki/Wiener_index>`_ |
|
.. [2] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, |
|
Croatica Chemica Acta, 71 (1998), 21-51. |
|
https://hrcak.srce.hr/132323 |
|
""" |
|
|
|
import itertools as it |
|
|
|
import networkx as nx |
|
|
|
__all__ = ["wiener_index", "schultz_index", "gutman_index"] |
|
|
|
|
|
@nx._dispatchable(edge_attrs="weight") |
|
def wiener_index(G, weight=None): |
|
"""Returns the Wiener index of the given graph. |
|
|
|
The *Wiener index* of a graph is the sum of the shortest-path |
|
(weighted) distances between each pair of reachable nodes. |
|
For pairs of nodes in undirected graphs, only one orientation |
|
of the pair is counted. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
|
|
weight : string or None, optional (default: None) |
|
If None, every edge has weight 1. |
|
If a string, use this edge attribute as the edge weight. |
|
Any edge attribute not present defaults to 1. |
|
The edge weights are used to computing shortest-path distances. |
|
|
|
Returns |
|
------- |
|
number |
|
The Wiener index of the graph `G`. |
|
|
|
Raises |
|
------ |
|
NetworkXError |
|
If the graph `G` is not connected. |
|
|
|
Notes |
|
----- |
|
If a pair of nodes is not reachable, the distance is assumed to be |
|
infinity. This means that for graphs that are not |
|
strongly-connected, this function returns ``inf``. |
|
|
|
The Wiener index is not usually defined for directed graphs, however |
|
this function uses the natural generalization of the Wiener index to |
|
directed graphs. |
|
|
|
Examples |
|
-------- |
|
The Wiener index of the (unweighted) complete graph on *n* nodes |
|
equals the number of pairs of the *n* nodes, since each pair of |
|
nodes is at distance one:: |
|
|
|
>>> n = 10 |
|
>>> G = nx.complete_graph(n) |
|
>>> nx.wiener_index(G) == n * (n - 1) / 2 |
|
True |
|
|
|
Graphs that are not strongly-connected have infinite Wiener index:: |
|
|
|
>>> G = nx.empty_graph(2) |
|
>>> nx.wiener_index(G) |
|
inf |
|
|
|
References |
|
---------- |
|
.. [1] `Wikipedia: Wiener Index <https://en.wikipedia.org/wiki/Wiener_index>`_ |
|
""" |
|
connected = nx.is_strongly_connected(G) if G.is_directed() else nx.is_connected(G) |
|
if not connected: |
|
return float("inf") |
|
|
|
spl = nx.shortest_path_length(G, weight=weight) |
|
total = sum(it.chain.from_iterable(nbrs.values() for node, nbrs in spl)) |
|
|
|
return total if G.is_directed() else total / 2 |
|
|
|
|
|
@nx.utils.not_implemented_for("directed") |
|
@nx.utils.not_implemented_for("multigraph") |
|
@nx._dispatchable(edge_attrs="weight") |
|
def schultz_index(G, weight=None): |
|
r"""Returns the Schultz Index (of the first kind) of `G` |
|
|
|
The *Schultz Index* [3]_ of a graph is the sum over all node pairs of |
|
distances times the sum of degrees. Consider an undirected graph `G`. |
|
For each node pair ``(u, v)`` compute ``dist(u, v) * (deg(u) + deg(v)`` |
|
where ``dist`` is the shortest path length between two nodes and ``deg`` |
|
is the degree of a node. |
|
|
|
The Schultz Index is the sum of these quantities over all (unordered) |
|
pairs of nodes. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
The undirected graph of interest. |
|
weight : string or None, optional (default: None) |
|
If None, every edge has weight 1. |
|
If a string, use this edge attribute as the edge weight. |
|
Any edge attribute not present defaults to 1. |
|
The edge weights are used to computing shortest-path distances. |
|
|
|
Returns |
|
------- |
|
number |
|
The first kind of Schultz Index of the graph `G`. |
|
|
|
Examples |
|
-------- |
|
The Schultz Index of the (unweighted) complete graph on *n* nodes |
|
equals the number of pairs of the *n* nodes times ``2 * (n - 1)``, |
|
since each pair of nodes is at distance one and the sum of degree |
|
of two nodes is ``2 * (n - 1)``. |
|
|
|
>>> n = 10 |
|
>>> G = nx.complete_graph(n) |
|
>>> nx.schultz_index(G) == (n * (n - 1) / 2) * (2 * (n - 1)) |
|
True |
|
|
|
Graph that is disconnected |
|
|
|
>>> nx.schultz_index(nx.empty_graph(2)) |
|
inf |
|
|
|
References |
|
---------- |
|
.. [1] I. Gutman, Selected properties of the Schultz molecular topological index, |
|
J. Chem. Inf. Comput. Sci. 34 (1994), 1087–1089. |
|
https://doi.org/10.1021/ci00021a009 |
|
.. [2] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, |
|
Croatica Chemica Acta, 71 (1998), 21-51. |
|
https://hrcak.srce.hr/132323 |
|
.. [3] H. P. Schultz, Topological organic chemistry. 1. |
|
Graph theory and topological indices of alkanes,i |
|
J. Chem. Inf. Comput. Sci. 29 (1989), 239–257. |
|
|
|
""" |
|
if not nx.is_connected(G): |
|
return float("inf") |
|
|
|
spl = nx.shortest_path_length(G, weight=weight) |
|
d = dict(G.degree, weight=weight) |
|
return sum(dist * (d[u] + d[v]) for u, info in spl for v, dist in info.items()) / 2 |
|
|
|
|
|
@nx.utils.not_implemented_for("directed") |
|
@nx.utils.not_implemented_for("multigraph") |
|
@nx._dispatchable(edge_attrs="weight") |
|
def gutman_index(G, weight=None): |
|
r"""Returns the Gutman Index for the graph `G`. |
|
|
|
The *Gutman Index* measures the topology of networks, especially for molecule |
|
networks of atoms connected by bonds [1]_. It is also called the Schultz Index |
|
of the second kind [2]_. |
|
|
|
Consider an undirected graph `G` with node set ``V``. |
|
The Gutman Index of a graph is the sum over all (unordered) pairs of nodes |
|
of nodes ``(u, v)``, with distance ``dist(u, v)`` and degrees ``deg(u)`` |
|
and ``deg(v)``, of ``dist(u, v) * deg(u) * deg(v)`` |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
|
|
weight : string or None, optional (default: None) |
|
If None, every edge has weight 1. |
|
If a string, use this edge attribute as the edge weight. |
|
Any edge attribute not present defaults to 1. |
|
The edge weights are used to computing shortest-path distances. |
|
|
|
Returns |
|
------- |
|
number |
|
The Gutman Index of the graph `G`. |
|
|
|
Examples |
|
-------- |
|
The Gutman Index of the (unweighted) complete graph on *n* nodes |
|
equals the number of pairs of the *n* nodes times ``(n - 1) * (n - 1)``, |
|
since each pair of nodes is at distance one and the product of degree of two |
|
vertices is ``(n - 1) * (n - 1)``. |
|
|
|
>>> n = 10 |
|
>>> G = nx.complete_graph(n) |
|
>>> nx.gutman_index(G) == (n * (n - 1) / 2) * ((n - 1) * (n - 1)) |
|
True |
|
|
|
Graphs that are disconnected |
|
|
|
>>> G = nx.empty_graph(2) |
|
>>> nx.gutman_index(G) |
|
inf |
|
|
|
References |
|
---------- |
|
.. [1] M.V. Diudeaa and I. Gutman, Wiener-Type Topological Indices, |
|
Croatica Chemica Acta, 71 (1998), 21-51. |
|
https://hrcak.srce.hr/132323 |
|
.. [2] I. Gutman, Selected properties of the Schultz molecular topological index, |
|
J. Chem. Inf. Comput. Sci. 34 (1994), 1087–1089. |
|
https://doi.org/10.1021/ci00021a009 |
|
|
|
""" |
|
if not nx.is_connected(G): |
|
return float("inf") |
|
|
|
spl = nx.shortest_path_length(G, weight=weight) |
|
d = dict(G.degree, weight=weight) |
|
return sum(dist * d[u] * d[v] for u, vinfo in spl for v, dist in vinfo.items()) / 2 |
|
|