Example #1
0
    def test_3state_prev(self):
        dtraj = np.array([0, 1, 2, 0, 3, 4])
        import deeptime.markov.tools.estimation as msmest
        for rev in [True, False]:
            hmm = init.discrete.metastable_from_data(dtraj,
                                                     n_hidden_states=3,
                                                     lagtime=1,
                                                     reversible=rev)
            assert msmana.is_transition_matrix(
                hmm.transition_model.transition_matrix)
            if rev:
                assert msmana.is_reversible(
                    hmm.transition_model.transition_matrix)
            assert np.allclose(hmm.output_probabilities.sum(axis=1), 1)

        for rev in [True, False]:
            C = TransitionCountEstimator(
                lagtime=1,
                count_mode="sliding").fit(dtraj).fetch_model().count_matrix
            C += msmest.prior_neighbor(C, 0.001)
            hmm = init.discrete.metastable_from_data(dtraj,
                                                     n_hidden_states=3,
                                                     lagtime=1,
                                                     reversible=rev)
            np.testing.assert_(
                msmana.is_transition_matrix(
                    hmm.transition_model.transition_matrix))
            if rev:
                np.testing.assert_(
                    msmana.is_reversible(
                        hmm.transition_model.transition_matrix))
            np.testing.assert_allclose(hmm.output_probabilities.sum(axis=1),
                                       1.)
Example #2
0
def test_with_almost_converged_stat_dist(sparse_mode):
    """ test for https://github.com/markovmodel/msmtools/issues/106 """
    from deeptime.markov.tools.analysis import committor, is_reversible
    from deeptime.markov.tools.flux import flux_matrix, to_netflux
    from deeptime.markov import reactive_flux, ReactiveFlux

    T = np.array([[
        0.2576419223095193, 0.2254214623509954, 0.248270708174756,
        0.2686659071647294
    ],
                  [
                      0.2233847186210225, 0.2130434781715344,
                      0.2793477268264001, 0.284224076381043
                  ],
                  [
                      0.2118717275169231, 0.2405661227681972,
                      0.2943396213976011, 0.2532225283172787
                  ],
                  [
                      0.2328617711043517, 0.2485926610067547,
                      0.2571819311236834, 0.2613636367652102
                  ]])
    if sparse_mode:
        T = csr_matrix(T)
    mu = np.array([
        0.2306979668517676, 0.2328013892993006, 0.2703312416016573,
        0.2661694022472743
    ])
    assert is_reversible(T)
    np.testing.assert_allclose(T.T.dot(mu).T, mu)
    np.testing.assert_equal(T.T.dot(mu).T, T.T.dot(mu))
    A = [0]
    B = [1]

    # forward committor
    qplus = committor(T, A, B, forward=True, mu=mu)
    # backward committor
    if is_reversible(T, mu=mu):
        qminus = 1.0 - qplus
    else:
        qminus = committor(T, A, B, forward=False, mu=mu)

    tpt_obj = reactive_flux(T, A, B)
    tpt_obj.major_flux(1.0)
    # gross flux
    grossflux = flux_matrix(T, mu, qminus, qplus, netflux=False)
    # net flux
    netflux = to_netflux(grossflux)

    F = ReactiveFlux(A,
                     B,
                     netflux,
                     stationary_distribution=mu,
                     qminus=qminus,
                     qplus=qplus,
                     gross_flux=grossflux)
    F.pathways(1.0)
Example #3
0
 def test_transition_matrix(self):
     for P in [
             self.hmsm_lag1.transition_matrix,
             self.hmsm_lag1.transition_matrix
     ]:
         assert is_transition_matrix(P)
         assert is_reversible(P)
Example #4
0
def test_transition_matrix(oom_msm_scenario):
    for msm in oom_msm_scenario.msms:
        P = msm.transition_matrix
        # should be ndarray by default
        np.testing.assert_(
            isinstance(P, np.ndarray)
            or isinstance(P, scipy.sparse.csr_matrix))
        # shape
        np.testing.assert_equal(P.shape, (msm.n_states, msm.n_states))
        # test transition matrix properties
        import deeptime.markov.tools.analysis as msmana
        np.testing.assert_(msmana.is_transition_matrix(P))
        np.testing.assert_(msmana.is_connected(P))
        # REVERSIBLE
        if msm.reversible:
            np.testing.assert_(msmana.is_reversible(P))
        # Test equality with model:
        from scipy.sparse import issparse
        if issparse(P):
            P = P.toarray()
        if msm.reversible:
            np.testing.assert_allclose(
                P, oom_msm_scenario.rmsmrev.transition_matrix)
        else:
            np.testing.assert_allclose(P,
                                       oom_msm_scenario.rmsm.transition_matrix)
Example #5
0
 def _transition_matrix_samples(self, msm):
     Psamples = msm.sample_f('transition_matrix')
     # shape
     assert np.array_equal(np.shape(Psamples), (self.nsamples, self.nstates, self.nstates))
     # consistency
     for P in Psamples:
         assert is_transition_matrix(P)
         assert is_reversible(P)
Example #6
0
 def test_transition_matrix(self):
     import deeptime.markov.tools.analysis as msmana
     for P in [
             self.hmm_lag1.transition_model.transition_matrix,
             self.hmm_lag10.transition_model.transition_matrix
     ]:
         np.testing.assert_(msmana.is_transition_matrix(P))
         np.testing.assert_(msmana.is_reversible(P))
Example #7
0
 def test_transition_matrix_samples(self):
     Psamples = np.array([m.transition_model.transition_matrix for m in self.bhmm])
     # shape
     assert np.array_equal(np.shape(Psamples), (self.n_samples, self.n_states, self.n_states))
     # consistency
     import deeptime.markov.tools.analysis as msmana
     for P in Psamples:
         assert msmana.is_transition_matrix(P)
         assert msmana.is_reversible(P)
Example #8
0
 def test_rdl_decomposition(self):
     P = self.bdc.transition_matrix
     assert is_reversible(P)
     mu = self.bdc.stationary_distribution
     """Non-reversible"""
     """k=None"""
     Rn, Dn, Ln = rdl_decomposition(P)
     Xn = np.dot(Ln, Rn)
     """Right-eigenvectors"""
     assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn))
     """Left-eigenvectors"""
     assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln))
     """Orthonormality"""
     assert_allclose(Xn, np.eye(self.dim))
     """Probability vector"""
     assert_allclose(np.sum(Ln[0, :]), 1.0)
     """k is not None"""
     Rn, Dn, Ln = rdl_decomposition(P, k=self.k)
     Xn = np.dot(Ln, Rn)
     """Right-eigenvectors"""
     assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn))
     """Left-eigenvectors"""
     assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln))
     """Orthonormality"""
     assert_allclose(Xn, np.eye(self.k))
     """Probability vector"""
     assert_allclose(np.sum(Ln[0, :]), 1.0)
     """Reversible"""
     """k=None"""
     Rn, Dn, Ln = rdl_decomposition(P, norm='reversible')
     assert Dn.dtype in (np.float32, np.float64)
     Xn = np.dot(Ln, Rn)
     """Right-eigenvectors"""
     assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn))
     """Left-eigenvectors"""
     assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln))
     """Orthonormality"""
     assert_allclose(Xn, np.eye(self.dim))
     """Probability vector"""
     assert_allclose(np.sum(Ln[0, :]), 1.0)
     """Reversibility"""
     assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
     """k is not None"""
     Rn, Dn, Ln = rdl_decomposition(P, norm='reversible', k=self.k)
     Xn = np.dot(Ln, Rn)
     """Right-eigenvectors"""
     assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn))
     """Left-eigenvectors"""
     assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln))
     """Orthonormality"""
     assert_allclose(Xn, np.eye(self.k))
     """Probability vector"""
     assert_allclose(np.sum(Ln[0, :]), 1.0)
     """Reversibility"""
     assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
Example #9
0
def test_is_reversible(sparse_mode):
    p = np.zeros(10)
    q = np.zeros(10)
    p[0:-1] = 0.5
    q[1:] = 0.5
    p[4] = 0.01
    q[6] = 0.1
    bdc = birth_death_chain(q, p, sparse=sparse_mode)
    assert_equal(sparse_mode, bdc.sparse)
    assert_equal(issparse(bdc.transition_matrix), sparse_mode)
    assert_(is_reversible(bdc.transition_matrix, bdc.stationary_distribution))
Example #10
0
 def _transition_matrix(self, 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 (np.all(P.shape == (msm.nstates, msm.nstates)))
     # test transition matrix properties
     assert (is_transition_matrix(P))
     assert (is_connected(P))
     # REVERSIBLE
     if msm.is_reversible:
         assert (is_reversible(P))
Example #11
0
 def test_transition_matrix_obs(self):
     assert np.array_equal(
         self.hmsm_lag1.transition_matrix_obs().shape,
         (self.hmsm_lag1.nstates_obs, self.hmsm_lag1.nstates_obs))
     assert np.array_equal(
         self.hmsm_lag10.transition_matrix_obs().shape,
         (self.hmsm_lag10.nstates_obs, self.hmsm_lag10.nstates_obs))
     for T in [
             self.hmsm_lag1.transition_matrix_obs(),
             self.hmsm_lag1.transition_matrix_obs(k=2),
             self.hmsm_lag10.transition_matrix_obs(),
             self.hmsm_lag10.transition_matrix_obs(k=4)
     ]:
         assert is_transition_matrix(T)
         assert is_reversible(T)
 def _transition_matrix_samples(self, msm, given_pi):
     Psamples = [s.transition_matrix for s in msm.samples]
     # shape
     assert np.array_equal(np.shape(Psamples), (self.nsamples, self.n_states, self.n_states))
     # consistency
     import deeptime.markov.tools.analysis as msmana
     for P in Psamples:
         assert msmana.is_transition_matrix(P)
         try:
             assert msmana.is_reversible(P)
         except AssertionError:
             # re-do calculation msmtools just performed to get details
             from deeptime.markov.tools.analysis import stationary_distribution
             mu = stationary_distribution(P)
             X = mu[:, np.newaxis] * P
             np.testing.assert_allclose(X, np.transpose(X), atol=1e-12,
                                        err_msg="P not reversible, given_pi={}".format(given_pi))
    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))
Example #14
0
 def _transition_matrix_samples(self, msm, given_pi):
     Psamples = msm.sample_f('transition_matrix')
     # shape
     assert np.array_equal(np.shape(Psamples),
                           (self.nsamples, self.nstates, self.nstates))
     # consistency
     for P in Psamples:
         assert is_transition_matrix(P)
         try:
             assert is_reversible(P)
         except AssertionError:
             mu = stationary_distribution(P)
             X = mu[:, np.newaxis] * P
             np.testing.assert_allclose(
                 X,
                 np.transpose(X),
                 atol=1e-12,
                 err_msg="P not reversible, given_pi={}".format(given_pi))
Example #15
0
    def P(self, value):
        self._P = value
        # check input
        if self._P is not None:
            from deeptime.markov.tools.analysis import is_transition_matrix
            if not is_transition_matrix(self._P, tol=1e-8):
                raise ValueError('T is not a transition matrix.')
            # set states
            self.nstates = _np.shape(self._P)[0]
            if self.reversible is None:
                from deeptime.markov.tools.analysis import is_reversible
                self.reversible = is_reversible(self._P)

            from scipy.sparse import issparse
            self.sparse = issparse(self._P)
        else:
            # set dummy values for not yet known attributes.
            self.nstates = 0
            self.sparse = False
Example #16
0
 def test_discrete_6_3(self):
     # 4x4 transition matrix
     n_states = 3
     P = np.array([[0.90, 0.10, 0.00, 0.00, 0.00, 0.00],
                   [0.20, 0.79, 0.01, 0.00, 0.00, 0.00],
                   [0.00, 0.01, 0.84, 0.15, 0.00, 0.00],
                   [0.00, 0.00, 0.05, 0.94, 0.01, 0.00],
                   [0.00, 0.00, 0.00, 0.02, 0.78, 0.20],
                   [0.00, 0.00, 0.00, 0.00, 0.10, 0.90]])
     # generate realization
     T = 10000
     dtrajs = [MarkovStateModel(P).simulate(T)]
     # estimate initial HMM with 2 states - should be identical to P
     hmm = init.discrete.metastable_from_data(dtrajs, n_states, 1)
     # Test stochasticity and reversibility
     Tij = hmm.transition_model.transition_matrix
     B = hmm.output_probabilities
     np.testing.assert_(msmana.is_transition_matrix(Tij))
     np.testing.assert_(msmana.is_reversible(Tij))
     np.testing.assert_allclose(B.sum(axis=1), np.ones(B.shape[0]))
Example #17
0
 def test_IsReversible(self):
     # create a reversible matrix
     self.assertTrue(is_reversible(self.T, self.mu),
                     "T should be reversible")
Example #18
0
 def test_is_reversible(self):
     self.assertTrue(is_reversible(self.T, tol=self.tol),
                     'matrix should be reversible')
Example #19
0
def _pcca_connected(P, n, pi=None):
    r"""PCCA+ spectral clustering method with optimized memberships [1]_

    Clusters the first n_cluster eigenvectors of a transition matrix in order to cluster the states.
    This function assumes that the transition matrix is fully connected.

    Parameters
    ----------
    P : ndarray (n,n)
        Transition matrix.
    n : int
        Number of clusters to group to.
    pi: ndarray(n,), optional, default=None
        Stationary distribution if available.

    Returns
    -------
    chi : ndarray (n x m)
        A matrix containing the probability or membership of each state to be assigned to each cluster.
        The rows sum to 1.

    References
    ----------
    [1] S. Roeblitz and M. Weber, Fuzzy spectral clustering by PCCA+:
        application to Markov state models and data classification.
        Adv Data Anal Classif 7, 147-179 (2013).
    """

    # test connectivity
    from deeptime.markov.tools.estimation import connected_sets

    labels = connected_sets(P)
    n_components = len(
        labels
    )  # (n_components, labels) = connected_components(P, connection='strong')
    if n_components > 1:
        raise ValueError(
            "Transition matrix is disconnected. Cannot use pcca_connected.")

    if pi is None:
        from deeptime.markov.tools.analysis import stationary_distribution
        pi = stationary_distribution(P)
    else:
        if pi.shape[0] != P.shape[0]:
            raise ValueError(
                f"Stationary distribution must span entire state space but got {pi.shape[0]} states "
                f"instead of {P.shape[0]}.")
        pi /= pi.sum()  # make sure it is normalized

    from deeptime.markov.tools.analysis import is_reversible

    if not is_reversible(P, mu=pi):
        raise ValueError(
            "Transition matrix does not fulfill detailed balance. "
            "Make sure to call pcca with a reversible transition matrix estimate"
        )
    # TODO: Susanna mentioned that she has a potential fix for nonreversible matrices by replacing each complex conjugate
    #      pair by the real and imaginary components of one of the two vectors. We could use this but would then need to
    #      orthonormalize all eigenvectors e.g. using Gram-Schmidt orthonormalization. Currently there is no theoretical
    #      foundation for this, so I'll skip it for now.

    # right eigenvectors, ordered
    from deeptime.markov.tools.analysis import eigenvectors

    evecs = eigenvectors(P, n)

    # orthonormalize
    for i in range(n):
        evecs[:, i] /= math.sqrt(np.dot(evecs[:, i] * pi, evecs[:, i]))
    # make first eigenvector positive
    evecs[:, 0] = np.abs(evecs[:, 0])

    # Is there a significant complex component?
    if not np.alltrue(np.isreal(evecs)):
        warnings.warn(
            "The given transition matrix has complex eigenvectors, so it doesn't exactly fulfill detailed balance. "
            "Forcing eigenvectors to be real and continuing. Be aware that this is not theoretically solid."
        )
    evecs = np.real(evecs)

    # create initial solution using PCCA+. This could have negative memberships
    chi, rot_matrix = _pcca_connected_isa(evecs, n)

    # optimize the rotation matrix with PCCA++.
    rot_matrix = _opt_soft(evecs, rot_matrix, n)

    # These memberships should be nonnegative
    memberships = np.dot(evecs[:, :], rot_matrix)

    # We might still have numerical errors. Force memberships to be in [0,1]
    memberships = np.clip(memberships, 0., 1.)

    for i in range(0, np.shape(memberships)[0]):
        memberships[i] /= np.sum(memberships[i])

    return memberships
Example #20
0
def compute_reactive_flux(
        transition_matrix: np.ndarray,
        source_states: Iterable[int],
        target_states: Iterable[int],
        stationary_distribution=None,
        qminus=None,
        qplus=None,
        transition_matrix_tolerance: Optional[float] = None) -> ReactiveFlux:
    r""" Computes the A->B reactive flux using transition path theory (TPT).

    Parameters
    ----------
    transition_matrix : (M, M) ndarray or scipy.sparse matrix
        The transition matrix.
    source_states : array_like
        List of integer state labels for set A
    target_states : array_like
        List of integer state labels for set B
    stationary_distribution : (M,) ndarray, optional, default=None
        Stationary vector. If None is computed from the transition matrix internally.
    qminus : (M,) ndarray (optional)
        Backward committor for A->B reaction
    qplus : (M,) ndarray (optional)
        Forward committor for A-> B reaction
    transition_matrix_tolerance : float, optional, default=None
        Tolerance with which is checked whether the input is actually a transition matrix. If None (default),
        no check is performed.

    Returns
    -------
    tpt: deeptime.markov.tools.flux.ReactiveFlux object
        A python object containing the reactive A->B flux network
        and several additional quantities, such as stationary probability,
        committors and set definitions.

    Notes
    -----
    The central object used in transition path theory is the forward and backward comittor function.

    TPT (originally introduced in :footcite:`weinan2006towards`) for continous systems has a
    discrete version outlined in :footcite:`metzner2009transition`. Here, we use the transition
    matrix formulation described in :footcite:`noe2009constructing`.

    See also
    --------
    ReactiveFlux

    References
    ----------
    .. footbibliography::
    """
    import deeptime.markov.tools.analysis as msmana

    source_states = ensure_array(source_states, dtype=int)
    target_states = ensure_array(target_states, dtype=int)

    if len(source_states) == 0 or len(target_states) == 0:
        raise ValueError('set A or B is empty')

    n_states = transition_matrix.shape[0]
    if len(source_states) > n_states or len(target_states) > n_states \
            or max(source_states) > n_states or max(target_states) > n_states:
        raise ValueError(
            'set A or B defines more states than the given transition matrix.')

    if transition_matrix_tolerance is not None and \
            msmana.is_transition_matrix(transition_matrix, tol=transition_matrix_tolerance):
        raise ValueError('given matrix T is not a transition matrix')

    # we can compute the following properties from either dense or sparse T
    # stationary dist
    if stationary_distribution is None:
        stationary_distribution = msmana.stationary_distribution(
            transition_matrix)
    # forward committor
    if qplus is None:
        qplus = msmana.committor(transition_matrix,
                                 source_states,
                                 target_states,
                                 forward=True)
    # backward committor
    if qminus is None:
        if msmana.is_reversible(transition_matrix, mu=stationary_distribution):
            qminus = 1.0 - qplus
        else:
            qminus = msmana.committor(transition_matrix,
                                      source_states,
                                      target_states,
                                      forward=False,
                                      mu=stationary_distribution)
    # gross flux
    grossflux = tptapi.flux_matrix(transition_matrix,
                                   stationary_distribution,
                                   qminus,
                                   qplus,
                                   netflux=False)
    # net flux
    netflux = to_netflux(grossflux)

    # construct flux object
    return ReactiveFlux(source_states,
                        target_states,
                        net_flux=netflux,
                        stationary_distribution=stationary_distribution,
                        qminus=qminus,
                        qplus=qplus,
                        gross_flux=grossflux)