Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/algorithms/centrality/subgraph_alg.py: 27%

63 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

1""" 

2Subraph centrality and communicability betweenness. 

3""" 

4import networkx as nx 

5from networkx.utils import not_implemented_for 

6 

7__all__ = [ 

8 "subgraph_centrality_exp", 

9 "subgraph_centrality", 

10 "communicability_betweenness_centrality", 

11 "estrada_index", 

12] 

13 

14 

15@not_implemented_for("directed") 

16@not_implemented_for("multigraph") 

17@nx._dispatch 

18def subgraph_centrality_exp(G): 

19 r"""Returns the subgraph centrality for each node of G. 

20 

21 Subgraph centrality of a node `n` is the sum of weighted closed 

22 walks of all lengths starting and ending at node `n`. The weights 

23 decrease with path length. Each closed walk is associated with a 

24 connected subgraph ([1]_). 

25 

26 Parameters 

27 ---------- 

28 G: graph 

29 

30 Returns 

31 ------- 

32 nodes:dictionary 

33 Dictionary of nodes with subgraph centrality as the value. 

34 

35 Raises 

36 ------ 

37 NetworkXError 

38 If the graph is not undirected and simple. 

39 

40 See Also 

41 -------- 

42 subgraph_centrality: 

43 Alternative algorithm of the subgraph centrality for each node of G. 

44 

45 Notes 

46 ----- 

47 This version of the algorithm exponentiates the adjacency matrix. 

48 

49 The subgraph centrality of a node `u` in G can be found using 

50 the matrix exponential of the adjacency matrix of G [1]_, 

51 

52 .. math:: 

53 

54 SC(u)=(e^A)_{uu} . 

55 

56 References 

57 ---------- 

58 .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, 

59 "Subgraph centrality in complex networks", 

60 Physical Review E 71, 056103 (2005). 

61 https://arxiv.org/abs/cond-mat/0504730 

62 

63 Examples 

64 -------- 

65 (Example from [1]_) 

66 >>> G = nx.Graph( 

67 ... [ 

68 ... (1, 2), 

69 ... (1, 5), 

70 ... (1, 8), 

71 ... (2, 3), 

72 ... (2, 8), 

73 ... (3, 4), 

74 ... (3, 6), 

75 ... (4, 5), 

76 ... (4, 7), 

77 ... (5, 6), 

78 ... (6, 7), 

79 ... (7, 8), 

80 ... ] 

81 ... ) 

82 >>> sc = nx.subgraph_centrality_exp(G) 

83 >>> print([f"{node} {sc[node]:0.2f}" for node in sorted(sc)]) 

84 ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] 

85 """ 

86 # alternative implementation that calculates the matrix exponential 

87 import scipy as sp 

88 

89 nodelist = list(G) # ordering of nodes in matrix 

90 A = nx.to_numpy_array(G, nodelist) 

91 # convert to 0-1 matrix 

92 A[A != 0.0] = 1 

93 expA = sp.linalg.expm(A) 

94 # convert diagonal to dictionary keyed by node 

95 sc = dict(zip(nodelist, map(float, expA.diagonal()))) 

96 return sc 

97 

98 

99@not_implemented_for("directed") 

100@not_implemented_for("multigraph") 

101@nx._dispatch 

102def subgraph_centrality(G): 

103 r"""Returns subgraph centrality for each node in G. 

104 

105 Subgraph centrality of a node `n` is the sum of weighted closed 

106 walks of all lengths starting and ending at node `n`. The weights 

107 decrease with path length. Each closed walk is associated with a 

108 connected subgraph ([1]_). 

109 

110 Parameters 

111 ---------- 

112 G: graph 

113 

114 Returns 

115 ------- 

116 nodes : dictionary 

117 Dictionary of nodes with subgraph centrality as the value. 

118 

119 Raises 

120 ------ 

121 NetworkXError 

122 If the graph is not undirected and simple. 

123 

124 See Also 

125 -------- 

126 subgraph_centrality_exp: 

127 Alternative algorithm of the subgraph centrality for each node of G. 

128 

129 Notes 

130 ----- 

131 This version of the algorithm computes eigenvalues and eigenvectors 

132 of the adjacency matrix. 

133 

134 Subgraph centrality of a node `u` in G can be found using 

135 a spectral decomposition of the adjacency matrix [1]_, 

136 

137 .. math:: 

138 

139 SC(u)=\sum_{j=1}^{N}(v_{j}^{u})^2 e^{\lambda_{j}}, 

140 

141 where `v_j` is an eigenvector of the adjacency matrix `A` of G 

142 corresponding to the eigenvalue `\lambda_j`. 

143 

144 Examples 

145 -------- 

146 (Example from [1]_) 

147 >>> G = nx.Graph( 

148 ... [ 

149 ... (1, 2), 

150 ... (1, 5), 

151 ... (1, 8), 

152 ... (2, 3), 

153 ... (2, 8), 

154 ... (3, 4), 

155 ... (3, 6), 

156 ... (4, 5), 

157 ... (4, 7), 

158 ... (5, 6), 

159 ... (6, 7), 

160 ... (7, 8), 

161 ... ] 

162 ... ) 

163 >>> sc = nx.subgraph_centrality(G) 

164 >>> print([f"{node} {sc[node]:0.2f}" for node in sorted(sc)]) 

165 ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] 

166 

167 References 

168 ---------- 

169 .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, 

170 "Subgraph centrality in complex networks", 

171 Physical Review E 71, 056103 (2005). 

172 https://arxiv.org/abs/cond-mat/0504730 

173 

174 """ 

175 import numpy as np 

176 

177 nodelist = list(G) # ordering of nodes in matrix 

178 A = nx.to_numpy_array(G, nodelist) 

179 # convert to 0-1 matrix 

180 A[np.nonzero(A)] = 1 

181 w, v = np.linalg.eigh(A) 

182 vsquare = np.array(v) ** 2 

183 expw = np.exp(w) 

184 xg = vsquare @ expw 

185 # convert vector dictionary keyed by node 

186 sc = dict(zip(nodelist, map(float, xg))) 

187 return sc 

188 

189 

190@not_implemented_for("directed") 

191@not_implemented_for("multigraph") 

192@nx._dispatch 

193def communicability_betweenness_centrality(G): 

194 r"""Returns subgraph communicability for all pairs of nodes in G. 

195 

196 Communicability betweenness measure makes use of the number of walks 

197 connecting every pair of nodes as the basis of a betweenness centrality 

198 measure. 

199 

200 Parameters 

201 ---------- 

202 G: graph 

203 

204 Returns 

205 ------- 

206 nodes : dictionary 

207 Dictionary of nodes with communicability betweenness as the value. 

208 

209 Raises 

210 ------ 

211 NetworkXError 

212 If the graph is not undirected and simple. 

213 

214 Notes 

215 ----- 

216 Let `G=(V,E)` be a simple undirected graph with `n` nodes and `m` edges, 

217 and `A` denote the adjacency matrix of `G`. 

218 

219 Let `G(r)=(V,E(r))` be the graph resulting from 

220 removing all edges connected to node `r` but not the node itself. 

221 

222 The adjacency matrix for `G(r)` is `A+E(r)`, where `E(r)` has nonzeros 

223 only in row and column `r`. 

224 

225 The subraph betweenness of a node `r` is [1]_ 

226 

227 .. math:: 

228 

229 \omega_{r} = \frac{1}{C}\sum_{p}\sum_{q}\frac{G_{prq}}{G_{pq}}, 

230 p\neq q, q\neq r, 

231 

232 where 

233 `G_{prq}=(e^{A}_{pq} - (e^{A+E(r)})_{pq}` is the number of walks 

234 involving node r, 

235 `G_{pq}=(e^{A})_{pq}` is the number of closed walks starting 

236 at node `p` and ending at node `q`, 

237 and `C=(n-1)^{2}-(n-1)` is a normalization factor equal to the 

238 number of terms in the sum. 

239 

240 The resulting `\omega_{r}` takes values between zero and one. 

241 The lower bound cannot be attained for a connected 

242 graph, and the upper bound is attained in the star graph. 

243 

244 References 

245 ---------- 

246 .. [1] Ernesto Estrada, Desmond J. Higham, Naomichi Hatano, 

247 "Communicability Betweenness in Complex Networks" 

248 Physica A 388 (2009) 764-774. 

249 https://arxiv.org/abs/0905.4102 

250 

251 Examples 

252 -------- 

253 >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) 

254 >>> cbc = nx.communicability_betweenness_centrality(G) 

255 >>> print([f"{node} {cbc[node]:0.2f}" for node in sorted(cbc)]) 

256 ['0 0.03', '1 0.45', '2 0.51', '3 0.45', '4 0.40', '5 0.19', '6 0.03'] 

257 """ 

258 import numpy as np 

259 import scipy as sp 

260 

261 nodelist = list(G) # ordering of nodes in matrix 

262 n = len(nodelist) 

263 A = nx.to_numpy_array(G, nodelist) 

264 # convert to 0-1 matrix 

265 A[np.nonzero(A)] = 1 

266 expA = sp.linalg.expm(A) 

267 mapping = dict(zip(nodelist, range(n))) 

268 cbc = {} 

269 for v in G: 

270 # remove row and col of node v 

271 i = mapping[v] 

272 row = A[i, :].copy() 

273 col = A[:, i].copy() 

274 A[i, :] = 0 

275 A[:, i] = 0 

276 B = (expA - sp.linalg.expm(A)) / expA 

277 # sum with row/col of node v and diag set to zero 

278 B[i, :] = 0 

279 B[:, i] = 0 

280 B -= np.diag(np.diag(B)) 

281 cbc[v] = B.sum() 

282 # put row and col back 

283 A[i, :] = row 

284 A[:, i] = col 

285 # rescale when more than two nodes 

286 order = len(cbc) 

287 if order > 2: 

288 scale = 1.0 / ((order - 1.0) ** 2 - (order - 1.0)) 

289 for v in cbc: 

290 cbc[v] *= scale 

291 return cbc 

292 

293 

294@nx._dispatch 

295def estrada_index(G): 

296 r"""Returns the Estrada index of a the graph G. 

297 

298 The Estrada Index is a topological index of folding or 3D "compactness" ([1]_). 

299 

300 Parameters 

301 ---------- 

302 G: graph 

303 

304 Returns 

305 ------- 

306 estrada index: float 

307 

308 Raises 

309 ------ 

310 NetworkXError 

311 If the graph is not undirected and simple. 

312 

313 Notes 

314 ----- 

315 Let `G=(V,E)` be a simple undirected graph with `n` nodes and let 

316 `\lambda_{1}\leq\lambda_{2}\leq\cdots\lambda_{n}` 

317 be a non-increasing ordering of the eigenvalues of its adjacency 

318 matrix `A`. The Estrada index is ([1]_, [2]_) 

319 

320 .. math:: 

321 EE(G)=\sum_{j=1}^n e^{\lambda _j}. 

322 

323 References 

324 ---------- 

325 .. [1] E. Estrada, "Characterization of 3D molecular structure", 

326 Chem. Phys. Lett. 319, 713 (2000). 

327 https://doi.org/10.1016/S0009-2614(00)00158-5 

328 .. [2] José Antonio de la Peñaa, Ivan Gutman, Juan Rada, 

329 "Estimating the Estrada index", 

330 Linear Algebra and its Applications. 427, 1 (2007). 

331 https://doi.org/10.1016/j.laa.2007.06.020 

332 

333 Examples 

334 -------- 

335 >>> G = nx.Graph([(0, 1), (1, 2), (1, 5), (5, 4), (2, 4), (2, 3), (4, 3), (3, 6)]) 

336 >>> ei = nx.estrada_index(G) 

337 >>> print(f"{ei:0.5}") 

338 20.55 

339 """ 

340 return sum(subgraph_centrality(G).values())