-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdistance_FC.py
More file actions
80 lines (65 loc) · 2.18 KB
/
distance_FC.py
File metadata and controls
80 lines (65 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import numpy as np
from numpy import linalg as LA
class distance_FC(object):
def __init__(self, FC1, FC2, eig_thresh=10 ** (-3)):
self.FC1 = FC1
self.FC2 = FC2
self.eig_thresh = eig_thresh
# ensure symmetric
self.FC1 = self._ensure_symmetric(self.FC1)
self.FC2 = self._ensure_symmetric(self.FC2)
def _info(self, s):
print('INFO: %s' % s)
def _ensure_symmetric(self, Q):
'''
computation is sometimes not precise (round errors),
so ensure matrices that are supposed to be
symmetric are symmetric
'''
return (Q + np.transpose(Q)) / 2
def _vectorize(self, Q):
'''
given a symmetric matrix (FC), return unique
elements as an array. Ignore diagonal elements
'''
# extract lower triangular matrix
tri = np.tril(Q, -1)
vec = []
for ii in range(1, tri.shape[0]):
for jj in range(ii):
vec.append(tri[ii, jj])
return np.asarray(vec)
def geodesic(self):
'''
dist = sqrt(trace(log^2(M)))
M = Q_1^{-1/2}*Q_2*Q_1^{-1/2}
'''
# compute Q_1^{-1/2} via eigen value decmposition
u, s, _ = LA.svd(self.FC1, full_matrices=True)
## lift very small eigen values
for ii, s_ii in enumerate(s):
if s_ii < self.eig_thresh:
s[ii] = self.eig_thresh
'''
since FC1 is in S+, u = v, u^{-1} = u'
FC1 = usu^(-1)
FC1^{1/2} = u[s^{1/2}]u'
FC1^{-1/2} = u[s^{-1/2}]u'
'''
FC1_mod = u @ np.diag(s ** (-1 / 2)) @ np.transpose(u)
M = FC1_mod @ self.FC2 @ FC1_mod
'''
trace = sum of eigenvalues;
np.logm might have round errors,
implement using svd instead
'''
_, s, _ = LA.svd(M, full_matrices=True)
return np.sqrt(np.sum(np.log(s) ** 2))
def pearson(self):
'''
conventional Pearson distance between
two FC matrices. The matrices are vectorized
'''
vec1 = self._vectorize(self.FC1)
vec2 = self._vectorize(self.FC2)
return (1 - np.corrcoef(vec1, vec2)[0, 1]) / 2