def test_with_almost_converged_stat_dist(self): """ test for #106 """ from msmtools.analysis import committor, is_reversible from msmtools.flux import tpt, flux_matrix, to_netflux, 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 ]]) mu = np.array([ 0.2306979668517676, 0.2328013892993006, 0.2703312416016573, 0.2661694022472743 ]) assert is_reversible(T) np.testing.assert_allclose(mu.dot(T), mu) np.testing.assert_equal(mu.dot(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 = tpt(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, mu=mu, qminus=qminus, qplus=qplus, gross_flux=grossflux) F.pathways(1.0)
def update(self, Tij, Pi=None): r""" Updates the transition matrix and recomputes all derived quantities """ # EMMA imports from msmtools import analysis as msmana # save a copy of the transition matrix self._Tij = np.array(Tij) assert msmana.is_transition_matrix( self._Tij), 'Given transition matrix is not a stochastic matrix' assert self._Tij.shape[ 0] == self._nstates, 'Given transition matrix has unexpected number of states ' # initial / stationary distribution if (Pi is not None): assert np.all( Pi >= 0 ), 'Given initial distribution contains negative elements.' Pi = np.array(Pi) / np.sum( Pi) # ensure normalization and make a copy if (self._stationary): pT = msmana.stationary_distribution(self._Tij) if Pi is None: # stationary and no stationary distribution fixed, so computing it from trans. mat. self._Pi = pT else: # stationary but stationary distribution is fixed, so the transition matrix must be consistent assert np.allclose(Pi, pT), 'Stationary HMM requested, but given distribution is not the ' \ 'stationary distribution of the given transition matrix.' self._Pi = Pi else: if Pi is None: # no initial distribution given, so use stationary distribution anyway self._Pi = msmana.stationary_distribution(self._Tij) else: self._Pi = Pi # reversible if self._reversible: assert msmana.is_reversible( Tij ), 'Reversible HMM requested, but given transition matrix is not reversible.' # try to do eigendecomposition by default, because it's very cheap for hidden transition matrices from scipy.linalg import LinAlgError try: if self._reversible: self._R, self._D, self._L = msmana.rdl_decomposition( self._Tij, norm='reversible') # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = msmana.rdl_decomposition( self._Tij, norm='standard') self._eigenvalues = np.diag(self._D) self._spectral_decomp_available = True except LinAlgError: logger().warn('Eigendecomposition failed for transition matrix\n' + str(self._Tij) + '\nspectral properties will not be available') self._spectral_decomp_available = False
def test_transition_matrix(self): import msmtools.analysis as msmana for P in [ self.hmsm_lag1.transition_matrix, self.hmsm_lag1.transition_matrix ]: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
def test_transition_matrix(self): """Test example transition matrices. """ Tij = testsystems.generate_transition_matrix(n_states=3, reversible=False) assert not is_reversible(Tij) Tij = testsystems.generate_transition_matrix(n_states=3, reversible=True) assert Tij.shape == (3, 3) assert is_transition_matrix(Tij)
def test_transition_matrix(self): import msmtools.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))
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 import msmtools.analysis as msmana for P in Psamples: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
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 msmana.is_transition_matrix(T) assert msmana.is_reversible(T)
def test_3state_prev(self): dtraj = np.array([0, 1, 2, 0, 3, 4]) import msmtools.estimation as msmest for rev in [True, False]: hmm = initial_guess_discrete_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 = initial_guess_discrete_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_model.output_probabilities.sum(axis=1), 1.)
def test_transition_matrix_samples(self): Psamples = self.sampled_hmm_lag10.transition_matrix_samples # shape assert np.array_equal(Psamples.shape, (self.nsamples, self.nstates, self.nstates)) # consistency import msmtools.analysis as msmana for P in Psamples: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
def test_transition_matrix_samples(self): Psamples = np.array([m.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 msmtools.analysis as msmana for P in Psamples: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
def test_3state_prev(self): import msmtools.analysis as msmana dtraj = np.array([0, 1, 2, 0, 3, 4]) C = msmest.count_matrix(dtraj, 1).toarray() for rev in [True, False]: hmm = init_discrete_hmm(dtraj, 3, reversible=rev) assert msmana.is_transition_matrix(hmm.transition_matrix) if rev: assert msmana.is_reversible(hmm.transition_matrix) assert np.allclose(hmm.output_model.output_probabilities.sum(axis=1), 1)
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)
def test_discrete_6_3(self): # 4x4 transition matrix nstates = 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 import msmtools.generation as msmgen T = 10000 dtrajs = [msmgen.generate_traj(P, T)] # estimate initial HMM with 2 states - should be identical to P hmm = initdisc.initial_model_discrete(dtrajs, nstates) # Test stochasticity and reversibility Tij = hmm.transition_matrix B = hmm.output_model.output_probabilities import msmtools.analysis as msmana msmana.is_transition_matrix(Tij) msmana.is_reversible(Tij) np.allclose(B.sum(axis=1), np.ones(B.shape[0]))
def transition_matrix(self, T): # Check transition matrix. if mana.is_transition_matrix(T): if not mana.is_reversible(T): warnings.warn("The transition matrix is not reversible.") if not mana.is_connected(T): warnings.warn("The transition matrix is not connected.") self._transition_matrix = T else: warnings.warn( "Not a transition matrix. Has to be square and rows must sum to one." )
def test_discrete_6_3(self): # 4x4 transition matrix nstates = 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 import msmtools.generation as msmgen T = 10000 dtrajs = [msmgen.generate_traj(P, T)] C = msmest.count_matrix(dtrajs, 1).toarray() # estimate initial HMM with 2 states - should be identical to P hmm = init_discrete_hmm(dtrajs, nstates) # Test stochasticity and reversibility Tij = hmm.transition_matrix B = hmm.output_model.output_probabilities import msmtools.analysis as msmana msmana.is_transition_matrix(Tij) msmana.is_reversible(Tij) np.allclose(B.sum(axis=1), np.ones(B.shape[0]))
def P(self, value): self._P = value import msmtools.analysis as msmana # check input if self._P is not None: if not msmana.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: self.reversible = msmana.is_reversible(self._P) from scipy.sparse import issparse self.sparse = issparse(self._P)
def update(self, Tij, Pi=None): r""" Updates the transition matrix and recomputes all derived quantities """ # EMMA imports from msmtools import analysis as msmana # save a copy of the transition matrix self._Tij = np.array(Tij) assert msmana.is_transition_matrix(self._Tij), 'Given transition matrix is not a stochastic matrix' assert self._Tij.shape[0] == self._nstates, 'Given transition matrix has unexpected number of states ' # initial / stationary distribution if (Pi is not None): assert np.all(Pi >= 0), 'Given initial distribution contains negative elements.' Pi = np.array(Pi) / np.sum(Pi) # ensure normalization and make a copy if (self._stationary): pT = msmana.stationary_distribution(self._Tij) if Pi is None: # stationary and no stationary distribution fixed, so computing it from trans. mat. self._Pi = pT else: # stationary but stationary distribution is fixed, so the transition matrix must be consistent assert np.allclose(Pi, pT), 'Stationary HMM requested, but given distribution is not the ' \ 'stationary distribution of the given transition matrix.' self._Pi = Pi else: if Pi is None: # no initial distribution given, so use stationary distribution anyway self._Pi = msmana.stationary_distribution(self._Tij) else: self._Pi = Pi # reversible if self._reversible: assert msmana.is_reversible(Tij), 'Reversible HMM requested, but given transition matrix is not reversible.' # try to do eigendecomposition by default, because it's very cheap for hidden transition matrices from scipy.linalg import LinAlgError try: if self._reversible: self._R, self._D, self._L = msmana.rdl_decomposition(self._Tij, norm='reversible') # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = msmana.rdl_decomposition(self._Tij, norm='standard') self._eigenvalues = np.diag(self._D) self._spectral_decomp_available = True except LinAlgError: logger().warn('Eigendecomposition failed for transition matrix\n'+str(self._Tij)+ '\nspectral properties will not be available') self._spectral_decomp_available = False
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.n_states, msm.n_states))) # test transition matrix properties import msmtools.analysis as msmana assert (msmana.is_transition_matrix(P)) assert (msmana.is_connected(P)) # REVERSIBLE if msm.reversible: assert (msmana.is_reversible(P))
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 msmtools.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 msmtools.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 transition_matrix(self, T): """Set transition matrix Parameters ---------- T : 2D numpy.ndarray. Transition matrix. Should be row stochastic and ergodic. """ # Check transition matrix. if mana.is_transition_matrix(T): if not mana.is_reversible(T): warnings.warn("The transition matrix is not reversible.") if not mana.is_connected(T): warnings.warn("The transition matrix is not connected.") else: warnings.warn( "Not a transition matrix. Has to be square and rows must sum to one." ) self._transition_matrix = T
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 = initial_guess_discrete_from_data(dtrajs, n_states, 1) # Test stochasticity and reversibility Tij = hmm.transition_model.transition_matrix B = hmm.output_model.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]))
def test_is_reversible(self): self.assertTrue(is_reversible(self.T, tol=self.tol), 'matrix should be reversible')
def test_transition_matrix(self): for P in [self.hmsm_lag1.transition_matrix, self.hmsm_lag1.transition_matrix]: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
def _pcca_connected(P, n, return_rot=False): """ 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. Returns ------- chi by default, or (chi,rot) if return_rot = True 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. rot_mat : ndarray (m x m) A rotation matrix that rotates the dominant eigenvectors to yield the PCCA memberships, i.e.: chi = np.dot(evec, rot_matrix 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 msmtools.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.") from msmtools.analysis import stationary_distribution pi = stationary_distribution(P) # print "statdist = ",pi from msmtools.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 msmtools.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) #print "initial chi = \n",chi # 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] # print "memberships unnormalized: ",memberships memberships = np.maximum(0.0, memberships) memberships = np.minimum(1.0, memberships) # print "memberships unnormalized: ",memberships for i in range(0, np.shape(memberships)[0]): memberships[i] /= np.sum(memberships[i]) # print "final chi = \n",chi return memberships
def set_model_params(self, P=None, pi=None, reversible=None, dt_model='1 step', neig=None): """ Call to set all basic model parameters. Sets or updates given model parameters. This argument list of this method must contain the full list of essential, or independent model parameters. It can additionally contain derived parameters, e.g. in order to save computational costs of re-computing them. Parameters ---------- P : ndarray(n,n) transition matrix pi : ndarray(n), optional, default=None stationary distribution. Can be optionally given in case if it was already computed, e.g. by the estimator. reversible : bool, optional, default=None whether P is reversible with respect to its stationary distribution. If None (default), will be determined from P dt_model : str, optional, default='1 step' Description of the physical time corresponding to the model time step. May be used by analysis algorithms such as plotting tools to pretty-print the axes. By default '1 step', i.e. there is no physical time unit. Specify by a number, whitespace and unit. Permitted units are (* is an arbitrary string): | 'fs', 'femtosecond*' | 'ps', 'picosecond*' | 'ns', 'nanosecond*' | 'us', 'microsecond*' | 'ms', 'millisecond*' | 's', 'second*' neig : int or None The number of eigenvalues / eigenvectors to be kept. If set to None, defaults will be used. For a dense MSM the default is all eigenvalues. For a sparse MSM the default is 10. Notes ----- Explicitly define all independent model parameters in the argument list of this function (by mandatory or keyword arguments) """ import msmtools.analysis as msmana # check input if P is not None: if not msmana.is_transition_matrix(P, tol=1e-8): raise ValueError('T is not a transition matrix.') # update all parameters self.update_model_params(P=P, pi=pi, reversible=reversible, dt_model=dt_model, neig=neig) # set ncv for consistency if not hasattr(self, 'ncv'): self.ncv = None # update derived quantities from pyemma.util.units import TimeUnit self._timeunit_model = TimeUnit(self.dt_model) # set P and derived quantities if available if P is not None: from scipy.sparse import issparse # set states self._nstates = np.shape(P)[0] if self.reversible is None: self.reversible = msmana.is_reversible(P) self.sparse = issparse(P) # set or correct eig param if neig is None: if self.sparse: self.neig = 10 else: self.neig = self._nstates
def tpt(T, A, B, mu=None, qminus=None, qplus=None, rate_matrix=False): r""" Computes the A->B reactive flux using transition path theory (TPT) Parameters ---------- T : (M, M) ndarray or scipy.sparse matrix Transition matrix (default) or Rate matrix (if rate_matrix=True) A : array_like List of integer state labels for set A B : array_like List of integer state labels for set B mu : (M,) ndarray (optional) Stationary vector qminus : (M,) ndarray (optional) Backward committor for A->B reaction qplus : (M,) ndarray (optional) Forward committor for A-> B reaction rate_matrix = False : boolean By default (False), T is a transition matrix. If set to True, T is a rate matrix. Returns ------- tpt: msmtools.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 [1]) for continous systems has a discrete version outlined in [2]. Here, we use the transition matrix formulation described in [3]. See also -------- msmtools.analysis.committor, ReactiveFlux References ---------- .. [1] W. E and E. Vanden-Eijnden. Towards a theory of transition paths. J. Stat. Phys. 123: 503-523 (2006) .. [2] P. Metzner, C. Schuette and E. Vanden-Eijnden. Transition Path Theory for Markov Jump Processes. Multiscale Model Simul 7: 1192-1219 (2009) .. [3] F. Noe, Ch. Schuette, E. Vanden-Eijnden, L. Reich and T. Weikl: Constructing the Full Ensemble of Folding Pathways from Short Off-Equilibrium Simulations. Proc. Natl. Acad. Sci. USA, 106, 19011-19016 (2009) """ import msmtools.analysis as msmana if len(A) == 0 or len(B) == 0: raise ValueError('set A or B is empty') n = T.shape[0] if len(A) > n or len(B) > n or max(A) > n or max(B) > n: raise ValueError( 'set A or B defines more states, than given transition matrix.') if (rate_matrix is False) and (not msmana.is_transition_matrix(T)): raise ValueError('given matrix T is not a transition matrix') if (rate_matrix is True): raise NotImplementedError( 'TPT with rate matrix is not yet implemented - But it is very simple, so feel free to do it.' ) # we can compute the following properties from either dense or sparse T # stationary dist if mu is None: mu = msmana.stationary_distribution(T) # forward committor if qplus is None: qplus = msmana.committor(T, A, B, forward=True) # backward committor if qminus is None: if msmana.is_reversible(T, mu=mu): qminus = 1.0 - qplus else: qminus = msmana.committor(T, A, B, forward=False, mu=mu) # gross flux grossflux = flux_matrix(T, mu, qminus, qplus, netflux=False) # net flux netflux = to_netflux(grossflux) # construct flux object from .reactive_flux import ReactiveFlux F = ReactiveFlux(A, B, netflux, mu=mu, qminus=qminus, qplus=qplus, gross_flux=grossflux) # done return F
def test_transition_matrix(self): import msmtools.analysis as msmana for P in [self.hmm_lag1.transition_matrix, self.hmm_lag1.transition_matrix]: assert msmana.is_transition_matrix(P) assert msmana.is_reversible(P)
def test_IsReversible(self): # create a reversible matrix self.assertTrue(is_reversible(self.T, self.mu), "T should be reversible")