Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/networkx/linalg/laplacianmatrix.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 """Laplacian matrix of graphs. | |
| 2 """ | |
| 3 # Copyright (C) 2004-2019 by | |
| 4 # Aric Hagberg <hagberg@lanl.gov> | |
| 5 # Dan Schult <dschult@colgate.edu> | |
| 6 # Pieter Swart <swart@lanl.gov> | |
| 7 # All rights reserved. | |
| 8 # BSD license. | |
| 9 import networkx as nx | |
| 10 from networkx.utils import not_implemented_for | |
| 11 __author__ = "\n".join(['Aric Hagberg <aric.hagberg@gmail.com>', | |
| 12 'Pieter Swart (swart@lanl.gov)', | |
| 13 'Dan Schult (dschult@colgate.edu)', | |
| 14 'Alejandro Weinstein <alejandro.weinstein@gmail.com>']) | |
| 15 __all__ = ['laplacian_matrix', | |
| 16 'normalized_laplacian_matrix', | |
| 17 'directed_laplacian_matrix', | |
| 18 'directed_combinatorial_laplacian_matrix'] | |
| 19 | |
| 20 | |
| 21 @not_implemented_for('directed') | |
| 22 def laplacian_matrix(G, nodelist=None, weight='weight'): | |
| 23 """Returns the Laplacian matrix of G. | |
| 24 | |
| 25 The graph Laplacian is the matrix L = D - A, where | |
| 26 A is the adjacency matrix and D is the diagonal matrix of node degrees. | |
| 27 | |
| 28 Parameters | |
| 29 ---------- | |
| 30 G : graph | |
| 31 A NetworkX graph | |
| 32 | |
| 33 nodelist : list, optional | |
| 34 The rows and columns are ordered according to the nodes in nodelist. | |
| 35 If nodelist is None, then the ordering is produced by G.nodes(). | |
| 36 | |
| 37 weight : string or None, optional (default='weight') | |
| 38 The edge data key used to compute each value in the matrix. | |
| 39 If None, then each edge has weight 1. | |
| 40 | |
| 41 Returns | |
| 42 ------- | |
| 43 L : SciPy sparse matrix | |
| 44 The Laplacian matrix of G. | |
| 45 | |
| 46 Notes | |
| 47 ----- | |
| 48 For MultiGraph/MultiDiGraph, the edges weights are summed. | |
| 49 | |
| 50 See Also | |
| 51 -------- | |
| 52 to_numpy_matrix | |
| 53 normalized_laplacian_matrix | |
| 54 laplacian_spectrum | |
| 55 """ | |
| 56 import scipy.sparse | |
| 57 if nodelist is None: | |
| 58 nodelist = list(G) | |
| 59 A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, | |
| 60 format='csr') | |
| 61 n, m = A.shape | |
| 62 diags = A.sum(axis=1) | |
| 63 D = scipy.sparse.spdiags(diags.flatten(), [0], m, n, format='csr') | |
| 64 return D - A | |
| 65 | |
| 66 | |
| 67 @not_implemented_for('directed') | |
| 68 def normalized_laplacian_matrix(G, nodelist=None, weight='weight'): | |
| 69 r"""Returns the normalized Laplacian matrix of G. | |
| 70 | |
| 71 The normalized graph Laplacian is the matrix | |
| 72 | |
| 73 .. math:: | |
| 74 | |
| 75 N = D^{-1/2} L D^{-1/2} | |
| 76 | |
| 77 where `L` is the graph Laplacian and `D` is the diagonal matrix of | |
| 78 node degrees. | |
| 79 | |
| 80 Parameters | |
| 81 ---------- | |
| 82 G : graph | |
| 83 A NetworkX graph | |
| 84 | |
| 85 nodelist : list, optional | |
| 86 The rows and columns are ordered according to the nodes in nodelist. | |
| 87 If nodelist is None, then the ordering is produced by G.nodes(). | |
| 88 | |
| 89 weight : string or None, optional (default='weight') | |
| 90 The edge data key used to compute each value in the matrix. | |
| 91 If None, then each edge has weight 1. | |
| 92 | |
| 93 Returns | |
| 94 ------- | |
| 95 N : NumPy matrix | |
| 96 The normalized Laplacian matrix of G. | |
| 97 | |
| 98 Notes | |
| 99 ----- | |
| 100 For MultiGraph/MultiDiGraph, the edges weights are summed. | |
| 101 See to_numpy_matrix for other options. | |
| 102 | |
| 103 If the Graph contains selfloops, D is defined as diag(sum(A,1)), where A is | |
| 104 the adjacency matrix [2]_. | |
| 105 | |
| 106 See Also | |
| 107 -------- | |
| 108 laplacian_matrix | |
| 109 normalized_laplacian_spectrum | |
| 110 | |
| 111 References | |
| 112 ---------- | |
| 113 .. [1] Fan Chung-Graham, Spectral Graph Theory, | |
| 114 CBMS Regional Conference Series in Mathematics, Number 92, 1997. | |
| 115 .. [2] Steve Butler, Interlacing For Weighted Graphs Using The Normalized | |
| 116 Laplacian, Electronic Journal of Linear Algebra, Volume 16, pp. 90-98, | |
| 117 March 2007. | |
| 118 """ | |
| 119 import scipy | |
| 120 import scipy.sparse | |
| 121 if nodelist is None: | |
| 122 nodelist = list(G) | |
| 123 A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, | |
| 124 format='csr') | |
| 125 n, m = A.shape | |
| 126 diags = A.sum(axis=1).flatten() | |
| 127 D = scipy.sparse.spdiags(diags, [0], m, n, format='csr') | |
| 128 L = D - A | |
| 129 with scipy.errstate(divide='ignore'): | |
| 130 diags_sqrt = 1.0 / scipy.sqrt(diags) | |
| 131 diags_sqrt[scipy.isinf(diags_sqrt)] = 0 | |
| 132 DH = scipy.sparse.spdiags(diags_sqrt, [0], m, n, format='csr') | |
| 133 return DH.dot(L.dot(DH)) | |
| 134 | |
| 135 ############################################################################### | |
| 136 # Code based on | |
| 137 # https://bitbucket.org/bedwards/networkx-community/src/370bd69fc02f/networkx/algorithms/community/ | |
| 138 | |
| 139 | |
| 140 @not_implemented_for('undirected') | |
| 141 @not_implemented_for('multigraph') | |
| 142 def directed_laplacian_matrix(G, nodelist=None, weight='weight', | |
| 143 walk_type=None, alpha=0.95): | |
| 144 r"""Returns the directed Laplacian matrix of G. | |
| 145 | |
| 146 The graph directed Laplacian is the matrix | |
| 147 | |
| 148 .. math:: | |
| 149 | |
| 150 L = I - (\Phi^{1/2} P \Phi^{-1/2} + \Phi^{-1/2} P^T \Phi^{1/2} ) / 2 | |
| 151 | |
| 152 where `I` is the identity matrix, `P` is the transition matrix of the | |
| 153 graph, and `\Phi` a matrix with the Perron vector of `P` in the diagonal and | |
| 154 zeros elsewhere. | |
| 155 | |
| 156 Depending on the value of walk_type, `P` can be the transition matrix | |
| 157 induced by a random walk, a lazy random walk, or a random walk with | |
| 158 teleportation (PageRank). | |
| 159 | |
| 160 Parameters | |
| 161 ---------- | |
| 162 G : DiGraph | |
| 163 A NetworkX graph | |
| 164 | |
| 165 nodelist : list, optional | |
| 166 The rows and columns are ordered according to the nodes in nodelist. | |
| 167 If nodelist is None, then the ordering is produced by G.nodes(). | |
| 168 | |
| 169 weight : string or None, optional (default='weight') | |
| 170 The edge data key used to compute each value in the matrix. | |
| 171 If None, then each edge has weight 1. | |
| 172 | |
| 173 walk_type : string or None, optional (default=None) | |
| 174 If None, `P` is selected depending on the properties of the | |
| 175 graph. Otherwise is one of 'random', 'lazy', or 'pagerank' | |
| 176 | |
| 177 alpha : real | |
| 178 (1 - alpha) is the teleportation probability used with pagerank | |
| 179 | |
| 180 Returns | |
| 181 ------- | |
| 182 L : NumPy array | |
| 183 Normalized Laplacian of G. | |
| 184 | |
| 185 Notes | |
| 186 ----- | |
| 187 Only implemented for DiGraphs | |
| 188 | |
| 189 See Also | |
| 190 -------- | |
| 191 laplacian_matrix | |
| 192 | |
| 193 References | |
| 194 ---------- | |
| 195 .. [1] Fan Chung (2005). | |
| 196 Laplacians and the Cheeger inequality for directed graphs. | |
| 197 Annals of Combinatorics, 9(1), 2005 | |
| 198 """ | |
| 199 import scipy as sp | |
| 200 from scipy.sparse import spdiags, linalg | |
| 201 | |
| 202 P = _transition_matrix(G, nodelist=nodelist, weight=weight, | |
| 203 walk_type=walk_type, alpha=alpha) | |
| 204 | |
| 205 n, m = P.shape | |
| 206 | |
| 207 evals, evecs = linalg.eigs(P.T, k=1) | |
| 208 v = evecs.flatten().real | |
| 209 p = v / v.sum() | |
| 210 sqrtp = sp.sqrt(p) | |
| 211 Q = spdiags(sqrtp, [0], n, n) * P * spdiags(1.0 / sqrtp, [0], n, n) | |
| 212 I = sp.identity(len(G)) | |
| 213 | |
| 214 return I - (Q + Q.T) / 2.0 | |
| 215 | |
| 216 | |
| 217 @not_implemented_for('undirected') | |
| 218 @not_implemented_for('multigraph') | |
| 219 def directed_combinatorial_laplacian_matrix(G, nodelist=None, weight='weight', | |
| 220 walk_type=None, alpha=0.95): | |
| 221 r"""Return the directed combinatorial Laplacian matrix of G. | |
| 222 | |
| 223 The graph directed combinatorial Laplacian is the matrix | |
| 224 | |
| 225 .. math:: | |
| 226 | |
| 227 L = \Phi - (\Phi P + P^T \Phi) / 2 | |
| 228 | |
| 229 where `P` is the transition matrix of the graph and and `\Phi` a matrix | |
| 230 with the Perron vector of `P` in the diagonal and zeros elsewhere. | |
| 231 | |
| 232 Depending on the value of walk_type, `P` can be the transition matrix | |
| 233 induced by a random walk, a lazy random walk, or a random walk with | |
| 234 teleportation (PageRank). | |
| 235 | |
| 236 Parameters | |
| 237 ---------- | |
| 238 G : DiGraph | |
| 239 A NetworkX graph | |
| 240 | |
| 241 nodelist : list, optional | |
| 242 The rows and columns are ordered according to the nodes in nodelist. | |
| 243 If nodelist is None, then the ordering is produced by G.nodes(). | |
| 244 | |
| 245 weight : string or None, optional (default='weight') | |
| 246 The edge data key used to compute each value in the matrix. | |
| 247 If None, then each edge has weight 1. | |
| 248 | |
| 249 walk_type : string or None, optional (default=None) | |
| 250 If None, `P` is selected depending on the properties of the | |
| 251 graph. Otherwise is one of 'random', 'lazy', or 'pagerank' | |
| 252 | |
| 253 alpha : real | |
| 254 (1 - alpha) is the teleportation probability used with pagerank | |
| 255 | |
| 256 Returns | |
| 257 ------- | |
| 258 L : NumPy array | |
| 259 Combinatorial Laplacian of G. | |
| 260 | |
| 261 Notes | |
| 262 ----- | |
| 263 Only implemented for DiGraphs | |
| 264 | |
| 265 See Also | |
| 266 -------- | |
| 267 laplacian_matrix | |
| 268 | |
| 269 References | |
| 270 ---------- | |
| 271 .. [1] Fan Chung (2005). | |
| 272 Laplacians and the Cheeger inequality for directed graphs. | |
| 273 Annals of Combinatorics, 9(1), 2005 | |
| 274 """ | |
| 275 from scipy.sparse import spdiags, linalg | |
| 276 | |
| 277 P = _transition_matrix(G, nodelist=nodelist, weight=weight, | |
| 278 walk_type=walk_type, alpha=alpha) | |
| 279 | |
| 280 n, m = P.shape | |
| 281 | |
| 282 evals, evecs = linalg.eigs(P.T, k=1) | |
| 283 v = evecs.flatten().real | |
| 284 p = v / v.sum() | |
| 285 Phi = spdiags(p, [0], n, n) | |
| 286 | |
| 287 Phi = Phi.todense() | |
| 288 | |
| 289 return Phi - (Phi*P + P.T*Phi) / 2.0 | |
| 290 | |
| 291 | |
| 292 def _transition_matrix(G, nodelist=None, weight='weight', | |
| 293 walk_type=None, alpha=0.95): | |
| 294 """Returns the transition matrix of G. | |
| 295 | |
| 296 This is a row stochastic giving the transition probabilities while | |
| 297 performing a random walk on the graph. Depending on the value of walk_type, | |
| 298 P can be the transition matrix induced by a random walk, a lazy random walk, | |
| 299 or a random walk with teleportation (PageRank). | |
| 300 | |
| 301 Parameters | |
| 302 ---------- | |
| 303 G : DiGraph | |
| 304 A NetworkX graph | |
| 305 | |
| 306 nodelist : list, optional | |
| 307 The rows and columns are ordered according to the nodes in nodelist. | |
| 308 If nodelist is None, then the ordering is produced by G.nodes(). | |
| 309 | |
| 310 weight : string or None, optional (default='weight') | |
| 311 The edge data key used to compute each value in the matrix. | |
| 312 If None, then each edge has weight 1. | |
| 313 | |
| 314 walk_type : string or None, optional (default=None) | |
| 315 If None, `P` is selected depending on the properties of the | |
| 316 graph. Otherwise is one of 'random', 'lazy', or 'pagerank' | |
| 317 | |
| 318 alpha : real | |
| 319 (1 - alpha) is the teleportation probability used with pagerank | |
| 320 | |
| 321 Returns | |
| 322 ------- | |
| 323 P : NumPy array | |
| 324 transition matrix of G. | |
| 325 | |
| 326 Raises | |
| 327 ------ | |
| 328 NetworkXError | |
| 329 If walk_type not specified or alpha not in valid range | |
| 330 """ | |
| 331 | |
| 332 import scipy as sp | |
| 333 from scipy.sparse import identity, spdiags | |
| 334 if walk_type is None: | |
| 335 if nx.is_strongly_connected(G): | |
| 336 if nx.is_aperiodic(G): | |
| 337 walk_type = "random" | |
| 338 else: | |
| 339 walk_type = "lazy" | |
| 340 else: | |
| 341 walk_type = "pagerank" | |
| 342 | |
| 343 M = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, | |
| 344 dtype=float) | |
| 345 n, m = M.shape | |
| 346 if walk_type in ["random", "lazy"]: | |
| 347 DI = spdiags(1.0 / sp.array(M.sum(axis=1).flat), [0], n, n) | |
| 348 if walk_type == "random": | |
| 349 P = DI * M | |
| 350 else: | |
| 351 I = identity(n) | |
| 352 P = (I + DI * M) / 2.0 | |
| 353 | |
| 354 elif walk_type == "pagerank": | |
| 355 if not (0 < alpha < 1): | |
| 356 raise nx.NetworkXError('alpha must be between 0 and 1') | |
| 357 # this is using a dense representation | |
| 358 M = M.todense() | |
| 359 # add constant to dangling nodes' row | |
| 360 dangling = sp.where(M.sum(axis=1) == 0) | |
| 361 for d in dangling[0]: | |
| 362 M[d] = 1.0 / n | |
| 363 # normalize | |
| 364 M = M / M.sum(axis=1) | |
| 365 P = alpha * M + (1 - alpha) / n | |
| 366 else: | |
| 367 raise nx.NetworkXError("walk_type must be random, lazy, or pagerank") | |
| 368 | |
| 369 return P | |
| 370 | |
| 371 | |
| 372 # fixture for pytest | |
| 373 def setup_module(module): | |
| 374 import pytest | |
| 375 numpy = pytest.importorskip('numpy') |
