Skip to content
This repository was archived by the owner on Sep 11, 2023. It is now read-only.

Commit bbcc076

Browse files
authored
Fixes (#1490)
* raise if n_jobs is non-positive (#1486) * [plots] deeptime compatibility for plot_flux * [its] shape fix * update pybind * include deeptime as dependency * fix regspace by using deeptime implementation * CI: update reference numpy and build distro for pip
1 parent 9f4781d commit bbcc076

File tree

11 files changed

+104
-25
lines changed

11 files changed

+104
-25
lines changed

.travis.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@ env:
1717
- MACOSX_DEPLOYMENT_TARGET=10.9
1818
- CONDA_BUILD=YES
1919
matrix:
20-
- CONDA_PY=3.6
21-
CONDA_NPY=1.11
22-
- CONDA_PY=3.7
23-
CONDA_NPY=1.17
20+
- CONDA_PY='3.6'
21+
CONDA_NPY='1.16'
22+
- CONDA_PY='3.7'
23+
CONDA_NPY='1.17'
24+
- CONDA_PY='3.8'
25+
CONDA_NPY='1.17'
2426

2527
matrix:
2628
exclude: # test only 3.8 on osx.
27-
- env: CONDA_PY=3.5
28-
os: osx
2929
- env: CONDA_PY=3.6
3030
os: osx
3131
include: # test pip install
3232
- env: CONDA_PY=3.7 CONDA_BUILD=NO python="3.7"
3333
os: linux
34-
dist: xenial # You’ll need to add dist: xenial to use Python 3.7 and higher.
34+
dist: bionic # You’ll need to add dist: bionic to use Python 3.7 and higher.
3535
language: python
3636
sudo: true
3737

devtools/conda-recipe/meta.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ requirements:
3535
- setuptools
3636
- pip
3737
- pybind11
38+
- deeptime
3839

3940
run:
40-
- bhmm >=0.6.3,<0.7
41+
- bhmm >=0.6.3
4142
- decorator >=4.0.0
4243
- h5py
4344
- intel-openmp # [osx]
@@ -52,6 +53,7 @@ requirements:
5253
- scipy
5354
- setuptools
5455
- tqdm
56+
- deeptime
5557

5658
test:
5759
source_files:

ext/pybind11

Submodule pybind11 updated 206 files

pyemma/coordinates/clustering/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@
3737
from .kmeans import KmeansClustering
3838
from .kmeans import MiniBatchKmeansClustering
3939
from .regspace import RegularSpaceClustering
40-
from .uniform_time import UniformTimeClustering
40+
from .uniform_time import UniformTimeClustering

pyemma/coordinates/clustering/interface.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ def _transform_array(self, X):
160160

161161
# for performance reasons we pre-center the cluster centers for minRMSD.
162162
if self.metric == 'minRMSD' and not self._precentered:
163-
self.logger.debug("precentering cluster centers for minRMSD.")
164-
self._inst.precenter_centers(self.clustercenters)
163+
# self.logger.debug("precentering cluster centers for minRMSD.")
164+
# self._inst.precenter_centers(self.clustercenters)
165165
self._precentered = True
166166

167167
dtraj = self._inst.assign(X, self.clustercenters, self.n_jobs)
@@ -279,7 +279,7 @@ def save_dtrajs(self, trajfiles=None, prefix='',
279279
output_files.append(name)
280280
else:
281281
for i in range(len(self.dtrajs)):
282-
if prefix is not '':
282+
if prefix != '':
283283
name = "%s_%i%s" % (prefix, i, extension)
284284
else:
285285
name = str(i) + extension

pyemma/coordinates/clustering/regspace.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from pyemma.util.exceptions import NotConvergedWarning
3232

3333
import numpy as np
34-
34+
import deeptime as dt
3535

3636
__all__ = ['RegularSpaceClustering']
3737

@@ -79,6 +79,10 @@ def __init__(self, dmin, max_centers=1000, metric='euclidean', stride=1, n_jobs=
7979
8080
"""
8181
super(RegularSpaceClustering, self).__init__(metric=metric, n_jobs=n_jobs)
82+
83+
from ._ext import RMSDMetric
84+
dt.clustering.metrics.register("minRMSD", RMSDMetric)
85+
8286
self._converged = False
8387
self.set_params(dmin=dmin, metric=metric,
8488
max_centers=max_centers, stride=stride, skip=skip)
@@ -133,16 +137,17 @@ def _estimate(self, iterable, **kwargs):
133137
# temporary list to store cluster centers
134138
clustercenters = []
135139
used_frames = 0
136-
from ._ext import regspace
137-
self._inst = regspace.Regspace_f(self.dmin, self.max_centers, self.metric, iterable.ndim)
140+
regspace = dt.clustering.RegularSpace(dmin=self.dmin, max_centers=self.max_centers,
141+
metric=self.metric, n_jobs=self.n_jobs)
142+
143+
# from ._ext import regspace
138144
it = iterable.iterator(return_trajindex=False, stride=self.stride,
139145
chunk=self.chunksize, skip=self.skip)
140146
try:
141147
with it:
142148
for X in it:
149+
regspace.partial_fit(X.astype(np.float32, order='C', copy=False), n_jobs=self.n_jobs)
143150
used_frames += len(X)
144-
self._inst.cluster(X.astype(np.float32, order='C', copy=False),
145-
clustercenters, self.n_jobs)
146151
self._converged = True
147152
except regspace.MaxCentersReachedException:
148153
self._converged = False
@@ -156,8 +161,16 @@ def _estimate(self, iterable, **kwargs):
156161
raise NotConvergedWarning("Used data for centers: %.2f%%" % used_data)
157162
finally:
158163
# even if not converged, we store the found centers.
159-
new_shape = (len(clustercenters), iterable.ndim)
160-
clustercenters = np.array(clustercenters).reshape(new_shape)
164+
model = regspace.fetch_model()
165+
clustercenters = model.cluster_centers.squeeze().reshape(-1, iterable.ndim)
166+
self._inst = dt.clustering.ClusterModel(clustercenters, metric=self.metric)
167+
from types import MethodType
168+
169+
def _assign(self, data, _, n_jobs):
170+
out = self.transform(data, n_jobs=n_jobs)
171+
return out
172+
173+
self._inst.assign = MethodType(_assign, self._inst)
161174
self.update_model_params(clustercenters=clustercenters,
162175
n_clusters=len(clustercenters))
163176

pyemma/coordinates/clustering/src/clustering_module.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,64 @@
22
// Created by marscher on 7/17/17.
33
//
44

5+
#include "metric.h"
56
#include "regspace.h"
67
#include "kmeans.h"
78

9+
class MaximumMetric : public Metric {
10+
public:
11+
12+
double compute_squared_d(const double* xs, const double* ys, std::size_t dim) const override {
13+
return _compute(xs, ys, dim);
14+
}
15+
float compute_squared_f(const float* xs, const float* ys, std::size_t dim) const override {
16+
return _compute(xs, ys, dim);
17+
}
18+
private:
19+
template<typename T>
20+
T _compute(const T* xs, const T* ys, std::size_t dim) const {
21+
T result = 0.0;
22+
for (size_t i = 0; i < dim; ++i) {
23+
auto d = std::abs(xs[i] - ys[i]);
24+
if (d > result) {
25+
result = d;
26+
}
27+
}
28+
return result*result;
29+
}
30+
};
31+
32+
class RMSDMetric : public Metric {
33+
public:
34+
35+
double compute_squared_d(const double* xs, const double* ys, std::size_t dim) const override {
36+
std::vector<float> xsCast (xs, xs+dim), ysCast (ys, ys+dim);
37+
return _compute(xsCast.data(), ysCast.data(), dim);
38+
}
39+
float compute_squared_f(const float* xs, const float* ys, std::size_t dim) const override {
40+
return _compute(xs, ys, dim);
41+
}
42+
43+
private:
44+
template<typename T>
45+
T _compute(const T* xs, const T* ys, std::size_t dim) const {
46+
if (dim % 3 != 0) {
47+
throw std::range_error("RMSDMetric is only implemented for input data with a dimension dividable by 3.");
48+
}
49+
float trace_a, trace_b;
50+
auto dim3 = static_cast<const int>(dim / 3);
51+
std::vector<float> buffer_b (ys, ys + dim);
52+
std::vector<float> buffer_a (xs, xs + dim);
53+
inplace_center_and_trace_atom_major(buffer_a.data(), &trace_a, 1, dim3);
54+
inplace_center_and_trace_atom_major(buffer_b.data(), &trace_b, 1, dim3);
55+
56+
57+
float msd = msd_atom_major(dim3, dim3, xs,
58+
buffer_b.data(), trace_a, trace_b, 0, nullptr);
59+
return msd;
60+
}
61+
};
62+
863
using dtype = float;
964

1065
PYBIND11_MODULE(_ext, m) {
@@ -36,4 +91,7 @@ PYBIND11_MODULE(_ext, m) {
3691
.def("cluster_loop", &kmeans_f::cluster_loop)
3792
.def("init_centers_KMpp", &kmeans_f::initCentersKMpp)
3893
.def("cost_function", &kmeans_f::costFunction);
94+
// py::class_<Metric>(m, "Metric");
95+
py::object baseMetric = (py::object) py::module_::import("deeptime.clustering._clustering_bindings").attr("Metric");
96+
py::class_<RMSDMetric>(m, "RMSDMetric", baseMetric).def(py::init<>());
3997
}

pyemma/msm/models/reactive_flux.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def dt_model(self, value):
107107
self._timeunit_model = TimeUnit(self._dt_model)
108108

109109
@property
110+
@alias('n_states')
110111
def nstates(self):
111112
r"""Returns the number of states.
112113

pyemma/plots/networks.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ def plot_flux(
544544
"""
545545
from matplotlib import pylab as plt
546546
F = flux_scale * getattr(flux, attribute_to_plot)
547-
c = flux.committor
547+
c = flux.forward_committor
548548
if state_sizes is None:
549549
state_sizes = flux.stationary_distribution
550550
plot = NetworkPlot(F, pos=pos, xpos=c, ax=ax)
@@ -554,13 +554,13 @@ def plot_flux(
554554

555555
if isinstance(state_labels, str) and state_labels == 'auto':
556556
# the first and last element correspond to A and B in ReactiveFlux
557-
state_labels = _np.array([str(i) for i in range(flux.nstates)])
557+
state_labels = _np.array([str(i) for i in range(flux.n_states)])
558558
state_labels[_np.array(flux.A)] = "A"
559559
state_labels[_np.array(flux.B)] = "B"
560560
elif isinstance(state_labels, (_np.ndarray, list, tuple)):
561-
if len(state_labels) != flux.nstates:
561+
if len(state_labels) != flux.n_states:
562562
raise ValueError("length of state_labels({}) has to match length of states({})."
563-
.format(len(state_labels), flux.nstates))
563+
.format(len(state_labels), flux.n_states))
564564

565565
fig = plot.plot_network(
566566
state_sizes=state_sizes, state_scale=state_scale, state_colors=state_colors,

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ requires = [
88
"mdtraj",
99
# TODO: include again once https://github.com/pybind/pybind11/issues/1067 is fixed.
1010
#"pybind11",
11+
"deeptime"
1112
]
1213

1314

0 commit comments

Comments
 (0)