Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/algorithms/centrality/second_order.py: 20%
30 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-10-20 07:00 +0000
1"""Copyright (c) 2015 – Thomson Licensing, SAS
3Redistribution and use in source and binary forms, with or without
4modification, are permitted (subject to the limitations in the
5disclaimer below) provided that the following conditions are met:
7* Redistributions of source code must retain the above copyright
8notice, this list of conditions and the following disclaimer.
10* Redistributions in binary form must reproduce the above copyright
11notice, this list of conditions and the following disclaimer in the
12documentation and/or other materials provided with the distribution.
14* Neither the name of Thomson Licensing, or Technicolor, nor the names
15of its contributors may be used to endorse or promote products derived
16from this software without specific prior written permission.
18NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
19GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
20HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31"""
33import networkx as nx
34from networkx.utils import not_implemented_for
36# Authors: Erwan Le Merrer (erwan.lemerrer@technicolor.com)
38__all__ = ["second_order_centrality"]
41@not_implemented_for("directed")
42@nx._dispatch(edge_attrs="weight")
43def second_order_centrality(G, weight="weight"):
44 """Compute the second order centrality for nodes of G.
46 The second order centrality of a given node is the standard deviation of
47 the return times to that node of a perpetual random walk on G:
49 Parameters
50 ----------
51 G : graph
52 A NetworkX connected and undirected graph.
54 weight : string or None, optional (default="weight")
55 The name of an edge attribute that holds the numerical value
56 used as a weight. If None then each edge has weight 1.
58 Returns
59 -------
60 nodes : dictionary
61 Dictionary keyed by node with second order centrality as the value.
63 Examples
64 --------
65 >>> G = nx.star_graph(10)
66 >>> soc = nx.second_order_centrality(G)
67 >>> print(sorted(soc.items(), key=lambda x: x[1])[0][0]) # pick first id
68 0
70 Raises
71 ------
72 NetworkXException
73 If the graph G is empty, non connected or has negative weights.
75 See Also
76 --------
77 betweenness_centrality
79 Notes
80 -----
81 Lower values of second order centrality indicate higher centrality.
83 The algorithm is from Kermarrec, Le Merrer, Sericola and Trédan [1]_.
85 This code implements the analytical version of the algorithm, i.e.,
86 there is no simulation of a random walk process involved. The random walk
87 is here unbiased (corresponding to eq 6 of the paper [1]_), thus the
88 centrality values are the standard deviations for random walk return times
89 on the transformed input graph G (equal in-degree at each nodes by adding
90 self-loops).
92 Complexity of this implementation, made to run locally on a single machine,
93 is O(n^3), with n the size of G, which makes it viable only for small
94 graphs.
96 References
97 ----------
98 .. [1] Anne-Marie Kermarrec, Erwan Le Merrer, Bruno Sericola, Gilles Trédan
99 "Second order centrality: Distributed assessment of nodes criticity in
100 complex networks", Elsevier Computer Communications 34(5):619-628, 2011.
101 """
102 import numpy as np
104 n = len(G)
106 if n == 0:
107 raise nx.NetworkXException("Empty graph.")
108 if not nx.is_connected(G):
109 raise nx.NetworkXException("Non connected graph.")
110 if any(d.get(weight, 0) < 0 for u, v, d in G.edges(data=True)):
111 raise nx.NetworkXException("Graph has negative edge weights.")
113 # balancing G for Metropolis-Hastings random walks
114 G = nx.DiGraph(G)
115 in_deg = dict(G.in_degree(weight=weight))
116 d_max = max(in_deg.values())
117 for i, deg in in_deg.items():
118 if deg < d_max:
119 G.add_edge(i, i, weight=d_max - deg)
121 P = nx.to_numpy_array(G)
122 P /= P.sum(axis=1)[:, np.newaxis] # to transition probability matrix
124 def _Qj(P, j):
125 P = P.copy()
126 P[:, j] = 0
127 return P
129 M = np.empty([n, n])
131 for i in range(n):
132 M[:, i] = np.linalg.solve(
133 np.identity(n) - _Qj(P, i), np.ones([n, 1])[:, 0]
134 ) # eq 3
136 return dict(
137 zip(G.nodes, [np.sqrt(2 * np.sum(M[:, i]) - n * (n + 1)) for i in range(n)])
138 ) # eq 6