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') |