Skip to content

Commit ae96e7c

Browse files
committed
[ENH] Added shortest path override
1 parent 3b4b5df commit ae96e7c

File tree

1 file changed

+154
-1
lines changed

1 file changed

+154
-1
lines changed

netneurotools/metrics.py

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,160 @@
77
import numpy as np
88
from scipy.linalg import expm
99
from scipy.stats import ttest_ind
10-
from bct import degrees_und
10+
from scipy.sparse.csgraph import shortest_path
11+
12+
try:
13+
from numba import njit
14+
use_numba = True
15+
except ImportError:
16+
use_numba = False
17+
18+
19+
def _binarize(W):
20+
"""
21+
Binarizes a matrix
22+
23+
Parameters
24+
----------
25+
W : (N, N) array_like
26+
Matrix to be binarized
27+
28+
Returns
29+
-------
30+
binarized : (N, N) numpy.ndarray
31+
Binarized matrix
32+
"""
33+
return (W > 0) * 1
34+
35+
36+
if use_numba:
37+
_binarize = njit(_binarize)
38+
39+
40+
def degrees_und(W):
41+
"""
42+
Computes the degree of each node in `W`
43+
44+
Parameters
45+
----------
46+
W : (N, N) array_like
47+
Unweighted, undirected connection weight array.
48+
Weighted array will be binarized prior to calculation.
49+
Directedness will be ignored (out degree / row sum taken).
50+
51+
Returns
52+
-------
53+
deg : (N,) numpy.ndarray
54+
Degree of each node in `W`
55+
"""
56+
return np.sum(_binarize(W), axis=0)
57+
58+
59+
def degrees_dir(W):
60+
"""
61+
Computes the in degree and out degree of each node in `W`
62+
63+
Parameters
64+
----------
65+
W : (N, N) array_like
66+
Unweighted, directed connection weight array.
67+
Weighted array will be binarized prior to calculation.
68+
69+
Returns
70+
-------
71+
deg_in : (N,) numpy.ndarray
72+
In-degree (column sum) of each node in `W`
73+
deg_out : (N,) numpy.ndarray
74+
Out-degree (row sum) of each node in `W`
75+
deg : (N,) numpy.ndarray
76+
Degree (in-degree + out-degree) of each node in `W`
77+
"""
78+
W_bin = _binarize(W)
79+
deg_in = np.sum(W_bin, axis=0)
80+
deg_out = np.sum(W_bin, axis=1)
81+
deg = deg_in + deg_out
82+
return deg_in, deg_out, deg
83+
84+
85+
def distance_wei_floyd(D):
86+
"""
87+
Computes the shortest path length between all pairs of nodes using
88+
Floyd-Warshall algorithm.
89+
90+
Parameters
91+
----------
92+
D : (N, N) array_like
93+
Connection length or distance matrix.
94+
Please do the weight-to-distance beforehand.
95+
96+
Returns
97+
-------
98+
spl_mat : (N, N) array_like
99+
Shortest path length matrix
100+
p_mat : (N, N) array_like
101+
Predecessor matrix returned from `scipy.sparse.csgraph.shortest_path`
102+
103+
Notes
104+
-----
105+
This function is a wrapper for `scipy.sparse.csgraph.shortest_path`.
106+
There may be more than one shortest path between two nodes, and we
107+
only return the first one found by the algorithm.
108+
109+
References
110+
----------
111+
.. [1] Floyd, R. W. (1962). Algorithm 97: shortest path. Communications of
112+
the ACM, 5(6), 345.
113+
.. [2] Roy, B. (1959). Transitivite et connexite. Comptes Rendus
114+
Hebdomadaires Des Seances De L Academie Des Sciences, 249(2), 216-218.
115+
.. [3] Warshall, S. (1962). A theorem on boolean matrices. Journal of the
116+
ACM (JACM), 9(1), 11-12.
117+
.. [4] https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
118+
119+
See Also
120+
--------
121+
netneurotools.metrics.retrieve_shortest_paths
122+
"""
123+
spl_mat, p_mat = shortest_path(
124+
D, method="FW", directed=False, return_predecessors=True,
125+
unweighted=False, overwrite=False
126+
)
127+
return spl_mat, p_mat
128+
129+
130+
def retrieve_shortest_paths(s, t, p_mat):
131+
"""
132+
Returns the shortest paths between two nodes.
133+
134+
Parameters
135+
----------
136+
s : int
137+
Source node
138+
t : int
139+
Target node
140+
p_mat : (N, N) array_like
141+
Predecessor matrix returned from `distance_wei_floyd`
142+
143+
Returns
144+
-------
145+
path : list of int
146+
List of nodes in the shortest path from `s` to `t`. If no path
147+
exists, returns `[-1]`.
148+
149+
See Also
150+
--------
151+
netneurotools.metrics.distance_wei_floyd
152+
"""
153+
if p_mat[s, t] == -9999:
154+
return [-1]
155+
path = [t]
156+
while path[-1] != s:
157+
t = p_mat[s, t]
158+
path.append(t)
159+
return path[::-1]
160+
161+
162+
if use_numba:
163+
retrieve_shortest_paths = njit(retrieve_shortest_paths)
11164

12165

13166
def communicability_bin(adjacency, normalize=False):

0 commit comments

Comments
 (0)