def test_correlation(self, setting): scenario = make_double_well(setting) msm = scenario.msm k = msm.n_states if not msm.sparse else 4 # raise assertion error because size is wrong: a = [1, 2, 3] with assert_raises(ValueError): msm.correlation(a, 1) maxtime = 100000 # should decrease a = list(range(msm.n_states)) times, corr1 = msm.correlation(a, maxtime=maxtime, k=k) assert_equal(len(corr1), maxtime / msm.lagtime) assert_equal(len(times), maxtime / msm.lagtime) assert_(corr1[0] > corr1[-1]) a = list(range(msm.n_states)) times, corr2 = msm.correlation(a, a, maxtime=maxtime, k=k) # should be identical to autocorr assert_almost_equal(corr1, corr2) # Test: should be increasing in time b = list(range(msm.n_states))[::-1] times, corr3 = msm.correlation(a, b, maxtime=maxtime, k=k) assert_equal(len(times), maxtime / msm.lagtime) assert_equal(len(corr3), maxtime / msm.lagtime) assert_(corr3[0] < corr3[-1])
def test_connected_sets(self, setting): scenario = make_double_well(setting) cs = scenario.msm.count_model.connected_sets() assert_equal(len(cs), 1) # mode largest: re-evaluating connected_sets should yield one connected set with exactly as many states as # contained in the count model assert_equal(cs[0], np.arange(scenario.msm.count_model.n_states))
def test_selected_count_fraction(self, setting): scenario = make_double_well(setting) # should always be a fraction assert_(0.0 <= scenario.msm.count_model.selected_count_fraction <= 1.0) # special case for this data set: assert_equal(scenario.msm.count_model.selected_count_fraction, scenario.selected_count_fraction)
def test_trajectory_weights(self, setting): scenario = make_double_well(setting) weights = scenario.msm.compute_trajectory_weights(scenario.data.dtraj) assert_almost_equal(weights[0].sum(), 1., decimal=6, err_msg="Weights should sum up to 1")
def test_relaxation(self, setting): scenario = make_double_well(setting) msm = scenario.msm if msm.sparse: k = 4 else: k = msm.n_states pi_perturbed = (msm.stationary_distribution**2) pi_perturbed /= pi_perturbed.sum() a = list(range(msm.n_states)) if isinstance(msm, AugmentedMSM): a = a[::-1] maxtime = 100000 times, rel1 = msm.relaxation(msm.stationary_distribution, a, maxtime=maxtime, k=k) # should be constant because we are in equilibrium assert_array_almost_equal(rel1 - rel1[0], np.zeros( (np.shape(rel1)[0]))) times, rel2 = msm.relaxation(pi_perturbed, a, maxtime=maxtime, k=k) # should relax assert_equal(len(times), maxtime / msm.count_model.lagtime) assert_equal(len(rel2), maxtime / msm.count_model.lagtime) assert_(rel2[0] < rel2[-1])
def test_discrete_trajectories_active(self, setting): scenario = make_double_well(setting) dta = scenario.msm.count_model.transform_discrete_trajectories_to_submodel( scenario.data.dtraj) assert_equal(len(dta), 1) # HERE: states are shifted down from the beginning, because early states are missing assert_(dta[0][0] < scenario.data.dtraj[0])
def test_expectation(self, setting): scenario = make_double_well(setting) if scenario.statdist_constraint: pytest.skip("no reference value for statdist constraint case.") assert_almost_equal(scenario.msm.expectation( list(range(scenario.msm.n_states))), scenario.expectation, decimal=2)
def test_simulate(self, setting): msm = make_double_well(setting).msm N = 400 start = 1 traj = msm.simulate(n_steps=N, start=start) assert_(len(traj) <= N) assert_(len(np.unique(traj)) <= msm.n_states) assert_equal(start, traj[0])
def test_state_symbols(self, setting): scenario = make_double_well(setting) # should always be <= full set assert_( len(scenario.msm.count_model.state_symbols) <= scenario.msm.count_model.n_states_full) # should be length of n_states assert_equal(len(scenario.msm.count_model.state_symbols), scenario.msm.count_model.n_states)
def test_compute_state_indices(self, setting): scenario = make_double_well(setting) dtrajs = [np.array([1, 0]), np.array([18, 19, 18, 33, 1, 0]), np.array([18, 19, 18, 1, 0])] ix = scenario.msm.compute_state_indices(dtrajs) for state, indices in enumerate(ix): for traj, frame in indices: assert_equal(dtrajs[traj][frame], scenario.msm.count_model.state_symbols[state]) with assert_raises(ValueError): scenario.msm.compute_state_indices(np.array([0] * 22)) # state 0 is not represented
def test_score(self, setting): scenario = make_double_well(setting) if isinstance(scenario.msm, AugmentedMSM): pytest.skip("scoring not implemented for augmented MSMs.") dtrajs_test = scenario.data.dtraj[80000:] scenario.msm.score(dtrajs_test) s1 = scenario.msm.score(dtrajs_test, r=1, dim=2) assert_(1.0 <= s1 <= 2.0) s2 = scenario.msm.score(dtrajs_test, r=2, dim=2) assert_(1.0 <= s2 <= 2.0)
def test_count_matrix(self, setting): scenario = make_double_well(setting) count_matrix_full = scenario.msm.count_model.count_matrix_full n = np.max(scenario.data.dtraj) + 1 assert_equal(count_matrix_full.shape, (n, n)) count_matrix = scenario.msm.count_model.count_matrix assert_equal(count_matrix.shape, (scenario.msm.n_states, scenario.msm.n_states)) if hasattr(scenario.msm, 'state_fraction'): # msm collection assert_equal(scenario.msm.state_fraction, scenario.msm.count_model.selected_state_fraction) assert_equal(scenario.msm.count_fraction, scenario.msm.count_model.selected_count_fraction)
def test_eigenvectors(self, setting): scenario = make_double_well(setting) msm = scenario.msm if not msm.sparse: k = msm.n_states L = msm.eigenvectors_left() D = np.diag(msm.eigenvalues()) R = msm.eigenvectors_right() else: k = 4 # maximum scipy can handle for sparse matrices L = msm.eigenvectors_left(k) D = np.diag(msm.eigenvalues(k)) R = msm.eigenvectors_right(k) # shape should be right assert_equal(L.shape, (k, msm.n_states)) assert_equal(R.shape, (msm.n_states, k)) # eigenvector properties assert_array_almost_equal(L[0, :], msm.stationary_distribution, err_msg="should be identical to stat. dist") assert_array_almost_equal(R[:, 0], np.ones(msm.n_states), err_msg="should be all ones") assert_array_almost_equal(np.sum(L[1:, :], axis=1), np.zeros(k - 1), err_msg="sums should be 1, 0, 0, ...") if msm.sparse: eye = np.real_if_close(np.dot(L, R), tol=10000) assert_array_almost_equal(eye, np.eye(k), decimal=1, err_msg="orthogonality constraint") else: assert_array_almost_equal(np.dot(L, R), np.eye(k), err_msg="orthogonality constraint") # recover transition matrix transition_matrix = msm.transition_matrix if msm.sparse: transition_matrix = transition_matrix.toarray() assert_array_almost_equal(np.dot(R, np.dot(D, L)), transition_matrix, decimal=0) else: assert_array_almost_equal(np.dot(R, np.dot(D, L)), transition_matrix) # REVERSIBLE: if msm.reversible: assert_(np.all(np.isreal(L))) assert_(np.all(np.isreal(R))) mu = msm.stationary_distribution L_mu = mu[:, np.newaxis] * R assert_array_almost_equal(np.dot(L_mu.T, R), np.eye(k))
def test_hmm_coarse_graining_sanity(self, setting): scenario = make_double_well(setting) reversible = scenario.msm.reversible sparse = scenario.msm.sparse if isinstance(scenario.msm, AugmentedMSM): assert_equal(scenario.msm.hmm, None) # not supported for AMMs elif reversible and not sparse: hmm = scenario.msm.hmm(scenario.data.dtraj, nhidden=2) assert_equal(hmm.n_hidden_states, 2) assert_equal(hmm.n_observation_states, scenario.msm.count_model.n_states_full) else: with assert_raises(ValueError): scenario.msm.hmm(scenario.data.dtraj, nhidden=2)
def test_active_state_indices(self, setting): scenario = make_double_well(setting) from deeptime.markov.sample import compute_index_states I = compute_index_states(scenario.data.dtraj, subset=scenario.msm.count_model.state_symbols) assert (len(I) == scenario.msm.n_states) # compare to histogram from deeptime.markov.util import count_states hist = count_states(scenario.data.dtraj) # number of frames should match on active subset A = scenario.msm.count_model.state_symbols for i in range(A.shape[0]): assert I[i].shape[0] == hist[A[i]] assert I[i].shape[1] == 2
def test_pcca(self, setting): scenario = make_double_well(setting) msm = scenario.msm if msm.reversible: pcca = msm.pcca(2) assignments = pcca.assignments # test: number of states assert_equal(len(assignments), msm.n_states) assert_equal(pcca.n_metastable, 2) # test: should be 0 or 1 assert_(np.all(assignments >= 0)) assert_(np.all(assignments <= 1)) # should be equal (zero variance) within metastable sets assert_(np.std(assignments[:30]) == 0) assert_(np.std(assignments[40:]) == 0) pccadist = pcca.metastable_distributions # should be right size assert_equal(pccadist.shape, (2, msm.n_states)) # should be nonnegative assert_(np.all(pccadist >= 0)) # should roughly add up to stationary: cgdist = np.array([ msm.stationary_distribution[pcca.sets[0]].sum(), msm.stationary_distribution[pcca.sets[1]].sum() ]) ds = cgdist[0] * pccadist[0] + cgdist[1] * pccadist[1] ds /= ds.sum() assert_array_almost_equal(ds, msm.stationary_distribution, decimal=3) memberships = pcca.memberships # should be right size assert_equal(memberships.shape, (msm.n_states, 2)) # should be nonnegative assert_(np.all(memberships >= 0)) # should add up to one: assert_array_almost_equal(memberships.sum(axis=1), np.ones(msm.n_states)) sets = pcca.sets assignment = pcca.assignments # should coincide with assignment for i, s in enumerate(sets): for j in range(len(s)): assert (assignment[s[j]] == i) else: with assert_raises(ValueError): msm.pcca(2)
def test_eigenvalues(self, setting): scenario = make_double_well(setting) # use n_states-2 because sparse eigenvalue problem can only be solved by scipy for k < N-1 ev = scenario.msm.eigenvalues(scenario.msm.n_states - 2) # stochasticity assert_(np.max(np.abs(ev)) <= 1 + 1e-12) # irreducible assert_(np.max(np.abs(ev[1:])) < 1) # ordered? evabs = np.abs(ev) for i in range(0, len(evabs) - 1): assert_(evabs[i] >= evabs[i + 1]) # REVERSIBLE: if scenario.msm.reversible: assert_(np.all(np.isreal(ev)))
def test_statdist(self, setting): scenario = make_double_well(setting) mu = scenario.msm.stationary_distribution # should strictly positive (irreversibility) assert_(np.all(mu > 0)) # should sum to one assert_almost_equal(np.sum(mu), 1., decimal=10) # in case it was an ML estimate with fixed stationary distribution it should be reproduced if isinstance(scenario.msm_estimator, MaximumLikelihoodMSM) \ and scenario.msm_estimator.stationary_distribution_constraint is not None: assert_array_almost_equal( scenario.msm.stationary_distribution, scenario.stationary_distribution[ scenario.msm.count_model.state_symbols])
def test_mfpt(self, setting): scenario = make_double_well(setting) if scenario.statdist_constraint: pytest.skip("timescales reference values only valid without constrained stationary distribution") a = 16 b = 48 t = scenario.msm.mfpt(a, b) assert_(t > 0) if isinstance(scenario.msm, AugmentedMSM): assert_allclose(t, 546.81, rtol=1e-3, atol=1e-6) else: if scenario.msm.reversible: assert_allclose(t, 872.69, rtol=1e-3, atol=1e-6) else: assert_allclose(t, 872.07, rtol=1e-3, atol=1e-6)
def test_transition_matrix(self, setting): scenario = make_double_well(setting) msm = scenario.msm P = msm.transition_matrix # should be ndarray by default # assert (isinstance(P, np.ndarray)) assert_(isinstance(P, np.ndarray) or isinstance(P, scipy.sparse.csr_matrix)) # shape assert_equal(P.shape, (msm.n_states, msm.n_states)) # test transition matrix properties import deeptime.markov.tools.analysis as msmana assert_(msmana.is_transition_matrix(P)) assert_(msmana.is_connected(P)) # REVERSIBLE if msm.reversible: assert_(msmana.is_reversible(P))
def test_committor(self, setting): scenario = make_double_well(setting) a = 16 b = 48 q_forward = scenario.msm.committor_forward(a, b) assert_equal(q_forward[a], 0) assert_equal(q_forward[b], 1) assert_(np.all(q_forward[:30] < 0.5)) assert_(np.all(q_forward[40:] > 0.5)) q_backward = scenario.msm.committor_backward(a, b) assert_equal(q_backward[a], 1) assert_equal(q_backward[b], 0) assert_(np.all(q_backward[:30] > 0.5)) assert_(np.all(q_backward[40:] < 0.5)) # REVERSIBLE: if scenario.msm.reversible: assert_(np.allclose(q_forward + q_backward, np.ones(scenario.msm.n_states)))
def test_timescales(self, setting): scenario = make_double_well(setting) if scenario.statdist_constraint: pytest.skip("timescales reference values only valid without constrained stationary distribution") msm = scenario.msm if not msm.sparse: ts = msm.timescales() else: k = 4 ts = msm.timescales(k) # should be all positive assert_(np.all(ts > 0)) if msm.reversible: # REVERSIBLE: should be all real assert_(np.all(np.isreal(ts))) assert_almost_equal(ts[:len(scenario.timescales)], scenario.timescales, decimal=2)
def test_fingerprint_relaxation(self, setting): scenario = make_double_well(setting) msm = scenario.msm if msm.sparse: k = 4 else: k = msm.n_states if msm.reversible: # raise assertion error because size is wrong: a = [1, 2, 3] with assert_raises(ValueError): msm.fingerprint_relaxation(msm.stationary_distribution, a, k=k) # equilibrium relaxation should be constant a = list(range(msm.n_states)) fp1 = msm.fingerprint_relaxation(msm.stationary_distribution, a, k=k) # first timescale is infinite assert_equal(fp1[0][0], np.inf) # next timescales are identical to timescales: assert_array_almost_equal(fp1[0][1:], msm.timescales(k - 1)) # dynamical amplitudes should be near 0 because we are in equilibrium assert_(np.max(np.abs(fp1[1][1:])) < 1e-10) # off-equilibrium relaxation pi_perturbed = (msm.stationary_distribution**2) pi_perturbed /= pi_perturbed.sum() fp2 = msm.fingerprint_relaxation(pi_perturbed, a, k=k) # first timescale is infinite assert_equal(fp2[0][0], np.inf) # next timescales are identical to timescales: assert_array_almost_equal(fp2[0][1:], msm.timescales(k - 1)) # dynamical amplitudes should be significant because we are not in equilibrium assert_(np.max(np.abs(fp2[1][1:])) > 0.1) else: # raise ValueError, because fingerprints are not defined for nonreversible with assert_raises(ValueError): a = list(range(msm.n_states)) msm.fingerprint_relaxation(msm.stationary_distribution, a, k=k) with assert_raises(ValueError): pi_perturbed = (msm.stationary_distribution**2) pi_perturbed /= pi_perturbed.sum() a = list(range(msm.n_states)) msm.fingerprint_relaxation(pi_perturbed, a)
def test_two_state_kinetics(self, setting): msm = make_double_well(setting).msm if msm.sparse: k = 4 else: k = msm.n_states # sanity check: k_forward + k_backward = 1.0/t2 for the two-state process l2 = msm.eigenvectors_left(k)[1, :] core1 = np.argmin(l2) core2 = np.argmax(l2) # transition time from left to right and vice versa t12 = msm.mfpt(core1, core2) t21 = msm.mfpt(core2, core1) # relaxation time t2 = msm.timescales(k)[0] # the following should hold roughly = k12 + k21 = k2. # sum of forward/backward rates can be a bit smaller because we are using small cores and # therefore underestimate rates ksum = 1.0 / t12 + 1.0 / t21 k2 = 1.0 / t2 assert_almost_equal(k2, ksum, decimal=3)
def test_fingerprint_correlation(self, setting): scenario = make_double_well(setting) msm = scenario.msm if msm.sparse: k = 4 else: k = msm.n_states if msm.reversible: # raise assertion error because size is wrong: a = [1, 2, 3] with assert_raises(ValueError): msm.fingerprint_correlation(a, 1, k=k) # should decrease a = list(range(msm.n_states)) fp1 = msm.fingerprint_correlation(a, k=k) # first timescale is infinite assert_equal(fp1[0][0], np.inf) # next timescales are identical to timescales: assert_array_almost_equal(fp1[0][1:], msm.timescales(k - 1)) # all amplitudes nonnegative (for autocorrelation) assert_(np.all(fp1[1][:] >= 0)) # identical call b = list(range(msm.n_states)) fp2 = msm.fingerprint_correlation(a, b, k=k) assert_almost_equal(fp1[0], fp2[0]) assert_almost_equal(fp1[1], fp2[1]) # should be - of the above, apart from the first b = list(range(msm.n_states))[::-1] fp3 = msm.fingerprint_correlation(a, b, k=k) assert_almost_equal(fp1[0], fp3[0]) assert_almost_equal(fp1[1][1:], -fp3[1][1:]) else: # raise ValueError, because fingerprints are not defined for nonreversible with assert_raises(ValueError): a = list(range(msm.n_states)) msm.fingerprint_correlation(a, k=k) with assert_raises(ValueError): a = list(range(msm.n_states)) b = list(range(msm.n_states)) msm.fingerprint_correlation(a, b, k=k)
def test_lagtime_property(self, setting): scenario = make_double_well(setting) assert_equal(scenario.msm.lagtime, scenario.lagtime)
def test_n_states_property(self, setting): scenario = make_double_well(setting) assert_( scenario.msm.n_states <= scenario.msm.count_model.n_states_full) assert_equal(scenario.msm.n_states, scenario.n_states)
def test_reversible_property(self, setting): scenario = make_double_well(setting) assert_equal(scenario.msm_estimator.reversible, scenario.msm.reversible)
def test_sparse_property(self, setting): scenario = make_double_well(setting) assert_equal(scenario.msm_estimator.sparse, scenario.msm.sparse)
def test_propagate(self, setting): scenario = make_double_well(setting) sd = scenario.msm.propagate(scenario.msm.stationary_distribution, 10) assert_array_almost_equal(sd, scenario.msm.stationary_distribution)