Skip to content

Commit 46ee34a

Browse files
authored
Misc (#153)
1 parent 8992601 commit 46ee34a

File tree

16 files changed

+133
-353
lines changed

16 files changed

+133
-353
lines changed

deeptime/data/_datasets.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,8 @@ def prinz_potential(h=1e-5, n_steps=500, temperature_factor=1., mass=1., damping
796796
797797
where :math:`m` is the mass, :math:`d` the damping factor, and :math:`\eta_t \sim \mathcal{N}(0, 1)`.
798798
799+
The locations of the minima can be accessed via the `minima` attribute.
800+
799801
.. plot:: datasets/plot_prinz.py
800802
801803
Parameters
@@ -844,11 +846,13 @@ def prinz_potential(h=1e-5, n_steps=500, temperature_factor=1., mass=1., damping
844846
.. footbibliography::
845847
"""
846848
from ._data_bindings import Prinz
847-
return TimeIndependentSystem(Prinz(), h, n_steps, props={
849+
system = TimeIndependentSystem(Prinz(), h, n_steps, props={
848850
'kT': temperature_factor,
849851
'mass': mass,
850852
'damping': damping
851853
})
854+
system.minima = [-0.73943018, -0.22373758, 0.26914935, 0.67329636]
855+
return system
852856

853857

854858
def triple_well_1d(h=1e-3, n_steps=500):

deeptime/markov/hmm/_bindings/include/OutputModelUtils.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,12 @@ std::tuple<np_array<dtype>, np_array<dtype>> fit(std::size_t nHiddenStates, cons
302302
for (decltype(nObsTrajs) k = 0; k < nObsTrajs; ++k, ++weightsIt, ++obsIt) {
303303
const auto &w = py::cast<np_array<dtype>>(*weightsIt);
304304
const auto &obs = py::cast<np_array<dtype>>(*obsIt);
305+
const auto* obsPtr = obs.data();
305306
for (decltype(nHiddenStates) i = 0; i < nHiddenStates; ++i) {
306307
dtype dot = 0;
307308
dtype wStateSum = 0;
308309
for (ssize_t t = 0; t < obs.shape(0); ++t) {
309-
dot += w.at(t, i) * obs.at(t);
310+
dot += w.at(t, i) * obsPtr[t];
310311
wStateSum += w.at(t, i);
311312
}
312313
// update nominator
@@ -329,12 +330,13 @@ std::tuple<np_array<dtype>, np_array<dtype>> fit(std::size_t nHiddenStates, cons
329330
for (decltype(nObsTrajs) k = 0; k < nObsTrajs; ++k, ++weightsIt, ++obsIt) {
330331
const auto &w = py::cast<np_array<dtype>>(*weightsIt);
331332
const auto &obs = py::cast<np_array<dtype>>(*obsIt);
333+
const auto *obsPtr = obs.data();
332334

333335
for (decltype(nHiddenStates) i = 0; i < nHiddenStates; ++i) {
334336
dtype wStateSum = 0;
335337
dtype sigmaUpdate = 0;
336338
for (ssize_t t = 0; t < obs.shape(0); ++t) {
337-
auto sqrty = static_cast<dtype>(obs.at(t)) - static_cast<dtype>(means.at(i));
339+
auto sqrty = static_cast<dtype>(obsPtr[t]) - static_cast<dtype>(means.at(i));
338340
sigmaUpdate += w.at(t, i) * sqrty*sqrty;
339341
wStateSum += w.at(t, i);
340342
}

deeptime/markov/hmm/init/gaussian/_init_gaussian_impl.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import numpy as np
22

33

4-
def from_data(dtrajs, n_hidden_states, reversible):
4+
def from_data(trajs, n_hidden_states, reversible):
55
r""" Makes an initial guess :class:`HMM <HiddenMarkovModel>` with Gaussian output model.
66
77
To this end, a Gaussian mixture model is estimated using `scikit-learn <https://scikit-learn.org/>`_.
88
99
Parameters
1010
----------
11-
dtrajs : array_like or list of array_like
11+
trajs : array_like or list of array_like
1212
Trajectories which are used for making the initial guess.
1313
n_hidden_states : int
1414
Number of hidden states.
@@ -32,15 +32,17 @@ def from_data(dtrajs, n_hidden_states, reversible):
3232
import deeptime.markov.tools.analysis as msmana
3333
from deeptime.util.types import ensure_timeseries_data
3434

35-
dtrajs = ensure_timeseries_data(dtrajs)
36-
collected_observations = np.concatenate(dtrajs)
35+
trajs = ensure_timeseries_data(trajs)
36+
collected_observations = np.concatenate(trajs)
37+
if collected_observations.ndim == 1:
38+
collected_observations = collected_observations[..., None]
3739
gmm = GaussianMixture(n_components=n_hidden_states)
38-
gmm.fit(collected_observations[:, None])
40+
gmm.fit(collected_observations)
3941
output_model = GaussianOutputModel(n_hidden_states, means=gmm.means_[:, 0], sigmas=np.sqrt(gmm.covariances_[:, 0]))
4042

4143
# Compute fractional state memberships.
4244
Nij = np.zeros((n_hidden_states, n_hidden_states))
43-
for o_t in dtrajs:
45+
for o_t in trajs:
4446
# length of trajectory
4547
T = o_t.shape[0]
4648
# output probability

deeptime/markov/tools/analysis/_api.py

+11-27
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
from ._decomposition import timescales_from_eigenvalues
1717

1818
from . import dense
19-
from . import sparse
2019
from . import _assessment
2120
from . import _mean_first_passage_time
2221
from . import _decomposition
2322
from . import _fingerprints
23+
from . import _committor
24+
from . import _expectations
2425

2526
__docformat__ = "restructuredtext en"
2627
__authors__ = __author__ = "Benjamin Trendelkamp-Schroer, Martin Scherer, Jan-Hendrik Prinz, Frank Noe"
@@ -739,26 +740,15 @@ def committor(T, A, B, forward=True, mu=None):
739740
T = ensure_number_array(T, ndim=2)
740741
A = ensure_integer_array(A, ndim=1)
741742
B = ensure_integer_array(B, ndim=1)
742-
if _issparse(T):
743-
if forward:
744-
return sparse.committor.forward_committor(T, A, B)
745-
else:
746-
""" if P is time reversible backward commitor is equal 1 - q+"""
747-
if is_reversible(T, mu=mu):
748-
return 1.0 - sparse.committor.forward_committor(T, A, B)
749-
750-
else:
751-
return sparse.committor.backward_committor(T, A, B)
752-
743+
if forward:
744+
return _committor.forward_committor(T, A, B)
753745
else:
754-
if forward:
755-
return dense.committor.forward_committor(T, A, B)
746+
""" if P is time reversible backward commitor is equal 1 - q+"""
747+
if is_reversible(T, mu=mu):
748+
return 1.0 - _committor.forward_committor(T, A, B)
749+
756750
else:
757-
""" if P is time reversible backward commitor is equal 1 - q+"""
758-
if is_reversible(T, mu=mu):
759-
return 1.0 - dense.committor.forward_committor(T, A, B)
760-
else:
761-
return dense.committor.backward_committor(T, A, B)
751+
return _committor.backward_committor(T, A, B)
762752

763753

764754
################################################################################
@@ -811,10 +801,7 @@ def expected_counts(T, p0, N):
811801
T = ensure_number_array(T, ndim=2)
812802
p0 = ensure_floating_array(p0, ndim=1)
813803
# go
814-
if _issparse(T):
815-
return sparse.expectations.expected_counts(p0, T, N)
816-
else:
817-
return dense.expectations.expected_counts(p0, T, N)
804+
return _expectations.expected_counts(p0, T, N)
818805

819806

820807
def expected_counts_stationary(T, N, mu=None):
@@ -867,10 +854,7 @@ def expected_counts_stationary(T, N, mu=None):
867854
if mu is not None:
868855
mu = ensure_floating_array(mu, ndim=1)
869856
# go
870-
if _issparse(T):
871-
return sparse.expectations.expected_counts_stationary(T, N, mu=mu)
872-
else:
873-
return dense.expectations.expected_counts_stationary(T, N, mu=mu)
857+
return _expectations.expected_counts_stationary(T, N, mu=mu)
874858

875859

876860
################################################################################

deeptime/markov/tools/analysis/dense/_committor.py deeptime/markov/tools/analysis/_committor.py

+38-31
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
1-
r"""This module provides functions for the computation of forward and
2-
backward comittors using dense linear algebra.
1+
import numpy as np
2+
from scipy.linalg import solve
3+
from scipy.sparse.linalg import spsolve
34

4-
.. moduleauthor:: B.Trendelkamp-Schroer <benjamin DOT trendelkamp-schroer AT fu-berlin DOT de>
5+
import scipy.sparse as sparse
56

6-
"""
7+
from ._stationary_vector import stationary_distribution
78

8-
import numpy as np
9-
from scipy.linalg import solve
109

11-
from .._stationary_vector import stationary_distribution
10+
def _set_up_linear_system(K, A, B):
11+
"""Assemble left-hand side W for linear system"""
12+
"""Equation (I)"""
13+
W = 1.0 * K
14+
"""Equation (II)"""
15+
if sparse.issparse(W):
16+
W = W.todok()
17+
W[list(A), :] = 0.0
18+
W.tocsr()
19+
W = W + sparse.coo_matrix((np.ones(len(A)), (list(A), list(A))), shape=W.shape).tocsr()
20+
else:
21+
W[list(A), :] = 0.0
22+
W[list(A), list(A)] = 1.0
23+
"""Equation (III)"""
24+
if sparse.issparse(W):
25+
W = W.todok()
26+
W[list(B), :] = 0.0
27+
W.tocsr()
28+
W = W + sparse.coo_matrix((np.ones(len(B)), (list(B), list(B))), shape=W.shape).tocsr()
29+
else:
30+
W[list(B), :] = 0.0
31+
W[list(B), list(B)] = 1.0
32+
return W
1233

1334

1435
def forward_committor(T, A, B):
@@ -49,28 +70,18 @@ def forward_committor(T, A, B):
4970
A = set(A)
5071
B = set(B)
5172
AB = A.intersection(B)
52-
notAB = X.difference(A).difference(B)
5373
if len(AB) > 0:
5474
raise ValueError("Sets A and B have to be disjoint")
5575
L = T - np.eye(T.shape[0]) # Generator matrix
5676

57-
"""Assemble left hand-side W for linear system"""
58-
"""Equation (I)"""
59-
W = 1.0 * L
60-
"""Equation (II)"""
61-
W[list(A), :] = 0.0
62-
W[list(A), list(A)] = 1.0
63-
"""Equation (III)"""
64-
W[list(B), :] = 0.0
65-
W[list(B), list(B)] = 1.0
66-
77+
W = _set_up_linear_system(L, A, B)
6778
"""Assemble right hand side r for linear system"""
6879
"""Equation (I+II)"""
6980
r = np.zeros(T.shape[0])
7081
"""Equation (III)"""
7182
r[list(B)] = 1.0
7283

73-
u = solve(W, r)
84+
u = solve(W, r) if not sparse.issparse(W) else spsolve(W, r)
7485
return u
7586

7687

@@ -115,29 +126,25 @@ def backward_committor(T, A, B, mu=None):
115126
A = set(A)
116127
B = set(B)
117128
AB = A.intersection(B)
118-
notAB = X.difference(A).difference(B)
119129
if len(AB) > 0:
120130
raise ValueError("Sets A and B have to be disjoint")
121131
if mu is None:
122132
mu = stationary_distribution(T)
123-
K = np.transpose(mu[:, np.newaxis] * (T - np.eye(T.shape[0])))
133+
if sparse.issparse(T):
134+
L = T - sparse.eye(T.shape[0], T.shape[0])
135+
D = sparse.diags([mu, ], [0, ])
136+
K = (D.dot(L)).T
137+
else:
138+
K = np.transpose(mu[:, np.newaxis] * (T - np.eye(T.shape[0])))
124139

125140
"""Assemble left-hand side W for linear system"""
126-
"""Equation (I)"""
127-
W = 1.0 * K
128-
"""Equation (II)"""
129-
W[list(A), :] = 0.0
130-
W[list(A), list(A)] = 1.0
131-
"""Equation (III)"""
132-
W[list(B), :] = 0.0
133-
W[list(B), list(B)] = 1.0
134-
141+
W = _set_up_linear_system(K, A, B)
135142
"""Assemble right-hand side r for linear system"""
136143
"""Equation (I)+(III)"""
137144
r = np.zeros(T.shape[0])
138145
"""Equation (II)"""
139146
r[list(A)] = 1.0
140147

141-
u = solve(W, r)
148+
u = solve(W, r) if not sparse.issparse(W) else spsolve(W, r)
142149

143150
return u

deeptime/markov/tools/analysis/dense/_expectations.py deeptime/markov/tools/analysis/_expectations.py

+28-13
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
"""
77

88
import numpy as np
9-
10-
from .._decomposition import rdl_decomposition
11-
from .._stationary_vector import stationary_distribution
9+
import scipy.sparse as sparse
10+
from ._decomposition import rdl_decomposition
11+
from ._stationary_vector import stationary_distribution
1212

1313

1414
def expected_counts(p0, T, n):
@@ -40,7 +40,7 @@ def expected_counts(p0, T, n):
4040
4141
"""
4242
M = T.shape[0]
43-
if n <= M:
43+
if sparse.issparse(T) or n <= M:
4444
return ec_matrix_vector(p0, T, n)
4545
else:
4646
return ec_geometric_series(p0, T, n)
@@ -72,12 +72,19 @@ def expected_counts_stationary(T, n, mu=None):
7272
7373
"""
7474
if n <= 0:
75-
EC = np.zeros(T.shape)
75+
if sparse.issparse(T):
76+
EC = sparse.coo_matrix(T.shape, dtype=float)
77+
else:
78+
EC = np.zeros(T.shape)
7679
return EC
7780
else:
7881
if mu is None:
79-
mu = stationary_distribution(T)
80-
EC = n * mu[:, np.newaxis] * T
82+
mu = stationary_distribution(T, check_inputs=False)
83+
if sparse.issparse(T):
84+
D_mu = sparse.diags(mu, 0)
85+
EC = n * D_mu.dot(T)
86+
else:
87+
EC = n * mu[:, np.newaxis] * T
8188
return EC
8289

8390

@@ -158,21 +165,29 @@ def ec_matrix_vector(p0, T, n):
158165
Expected value for transition counts after N steps.
159166
160167
"""
161-
if (n <= 0):
162-
EC = np.zeros(T.shape)
163-
return EC
168+
if n <= 0:
169+
if sparse.issparse(T):
170+
return sparse.coo_matrix(T.shape, dtype=float)
171+
else:
172+
return np.zeros(T.shape)
164173
else:
165174
"""Probability vector after (k=0) propagations"""
166175
p_k = 1.0 * p0
167176
"""Sum of vectors after (k=0) propagations"""
168177
p_sum = 1.0 * p_k
178+
"""Transpose T to use sparse dot product"""
179+
Tt = T.transpose()
169180
for k in range(n - 1):
170181
"""Propagate one step p_{k} -> p_{k+1}"""
171-
p_k = np.dot(p_k, T)
182+
p_k = Tt.dot(p_k)
172183
"""Update sum"""
173184
p_sum += p_k
174185
"""Expected counts"""
175-
EC = p_sum[:, np.newaxis] * T
186+
if sparse.issparse(T):
187+
D_psum = sparse.diags(p_sum, 0)
188+
EC = D_psum.dot(T)
189+
else:
190+
EC = p_sum[:, np.newaxis] * T
176191
return EC
177192

178193

@@ -208,7 +223,7 @@ def ec_geometric_series(p0, T, n):
208223
Expected value for transition counts after N steps.
209224
210225
"""
211-
if (n <= 0):
226+
if n <= 0:
212227
EC = np.zeros(T.shape)
213228
return EC
214229
else:
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
from . import _committor as committor
21
from . import _correlations as correlations
3-
from . import _expectations as expectations
42
from . import _hitting_probability as hitting_probability
53
from . import _sensitivity as sensitivity
64
from . import _pcca as pcca

deeptime/markov/tools/analysis/sparse/__init__.py

-2
This file was deleted.

0 commit comments

Comments
 (0)