-
Notifications
You must be signed in to change notification settings - Fork 658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Diffusion Map Refactor/Implementation #863
Changes from 1 commit
c511ead
3be892e
3ce705a
328c27a
d2d4593
ed5f4c5
2947c0f
7e94a58
ab7f93c
43144e0
18c84ee
0da96fa
2c93f2d
49578a0
7ec486a
f350eaa
245d2e8
17fced2
14b08e4
cfcbfe0
07a83d1
6faec56
48c27a9
fe08866
cafeb68
bb394ec
074a950
68f2928
98e899b
b893244
7b12ece
e5a3487
cbf685d
e0ed7b4
303b816
01dc0d5
2f2db09
34b1e7c
7c56863
bd40f38
420edd0
c058c6c
b6c309a
8ba1a58
aa22772
97c3105
b3b2ce9
c5d1958
d7cd454
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -260,8 +260,7 @@ class DiffusionMap(object): | |
the collective coordinates. | ||
""" | ||
|
||
def __init__(self, u, epsilon=1, manifold_density=None, | ||
timescale=1, **kwargs): | ||
def __init__(self, u, epsilon=1, **kwargs): | ||
""" | ||
Parameters | ||
------------- | ||
|
@@ -273,10 +272,6 @@ def __init__(self, u, epsilon=1, manifold_density=None, | |
epsilon : Float | ||
Specifies the method used for the choice of scale parameter in the | ||
diffusion map. More information in [1], [2] and [3], Default: 1. | ||
manifold_density: list, optional | ||
The list has to have the same length as the trajectory. | ||
With 'None' the weight of each frame of the trajectory will be the | ||
same, Default : None | ||
timescale: int, optional | ||
The number of steps in the random walk, large t reflects global | ||
structure whereas small t indicates local structure, Default: 1 | ||
|
@@ -296,21 +291,6 @@ def __init__(self, u, epsilon=1, manifold_density=None, | |
"be very slow to compute. Consider picking a larger " | ||
"step size in distance matrix initialization.") | ||
|
||
# determines length of diffusion process | ||
self._timescale = timescale | ||
|
||
if manifold_density is None: | ||
# weights do not apply to metric but density of data | ||
self._weights_ker = np.ones((self._nframes,)) | ||
else: | ||
if manifold_density.shape[0] != self._nframes: | ||
raise ValueError("The weight should have the same length as " | ||
'the trajectory') | ||
else: | ||
# density weights are constructed as relative to the mean | ||
self._weights_ker = (np.asarray(manifold_density, | ||
dtype=np.float64) / | ||
np.mean(manifold_density)) | ||
|
||
def run(self): | ||
# run only if distance matrix not already calculated | ||
|
@@ -320,33 +300,9 @@ def run(self): | |
self._epsilon) | ||
# take negative exponent of scaled matrix to create Isotropic kernel | ||
self._kernel = np.exp(-self._scaled_matrix) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why saving the |
||
# define an anistropic diffusion term q | ||
q_vector = np.zeros((self._nframes, )) | ||
# weights should reflect the density of the points on the manifold | ||
for i in range(self._nframes): | ||
q_vector[i] = np.dot(self._kernel[i, :], self._weights_ker) | ||
|
||
# Form a new kernel from the anisotropic diffusion term q | ||
self._kernel /= (np.sqrt(q_vector[:, np.newaxis | ||
].dot(q_vector[np.newaxis]))) | ||
|
||
# Weighted Graph Laplacian normalization on this new graph | ||
d_vector = np.zeros((self._nframes, )) | ||
for i in range(self._nframes): | ||
d_vector[i] = np.dot(self._kernel[i, :], self._weights_ker) | ||
|
||
for i in range(self._nframes): | ||
self._kernel[i, :] = self._kernel[i, :] * self._weights_ker | ||
|
||
# Define anisotropic transition by dividing kernel by this term | ||
self._kernel /= np.sqrt(d_vector[:, np.newaxis].dot(d_vector[np.newaxis])) | ||
|
||
# Apply timescaling | ||
if self._timescale > 1: | ||
self._kernel = np.linalg.matrix_power(self._kernel, | ||
self._timescale) | ||
|
||
eigenvals, eigenvectors = np.linalg.eig(self._kernel) | ||
D_inv = np.diag(1 / self._kernel.sum(1)) | ||
self._diff = np.dot(D_inv, self._kernel) | ||
eigenvals, eigenvectors = np.linalg.eig(self._diff) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't you say it's better to use eigh? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did and apparently I may have been wrong, the two give different results:
Eigenvalues using epsilon = 5, eig:
Given that the first eigenvalue should be 1 I am weary of using eigh |
||
eg_arg = np.argsort(eigenvals) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can already change the sorting direction here. Since these are indices it would also be nice if the name reflects that. |
||
self.eigenvalues = eigenvals[eg_arg[::-1]] | ||
self.eigenvectors = eigenvectors[eg_arg[::-1]] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why a default of 1? What unit is the epsilon?