def is_reversible(T, mu=None, tol=1e-15): r""" checks whether T is reversible in terms of given stationary distribution. If no distribution is given, it will be calculated out of T. performs follwing check: :math:`\pi_i P_{ij} = \pi_j P_{ji} Parameters ---------- T : scipy.sparse matrix Transition matrix mu : numpy.ndarray vector stationary distribution tol : float tolerance to check with Returns ------- Truth value : bool True, if T is a stochastic matrix False, otherwise """ if not is_transition_matrix(T, tol): raise ValueError("given matrix is not a valid transition matrix.") T = T.tocsr() if mu is None: from decomposition import stationary_distribution_from_backward_iteration as statdist mu = statdist(T) Mu = diags(mu, 0) prod = Mu * T return allclose_sparse(prod, prod.transpose(), rtol=tol)
def expected_counts_stationary(T, n, mu=None): r"""Expected transition counts for Markov chain in equilibrium. Since mu is stationary for T we have .. math:: E(C^{(N)})=N diag(mu)*T. Parameters ---------- T : (M, M) ndarray Transition matrix. n : int Number of steps for chain. mu : (M,) ndarray (optional) Stationary distribution for T. If mu is not specified it will be computed via diagonalization of T. Returns ------- EC : numpy array, shape=(n,n) Expected value for transition counts after a propagation of n steps. """ if n <= 0: EC = np.zeros(T.shape) return EC else: if mu is None: mu = statdist(T) EC = n * mu[:, np.newaxis] * T return EC
def expected_counts_stationary(T, n, mu=None): r"""Expected transition counts for Markov chain in equilibrium. Since mu is stationary for T we have .. math:: E(C^{(N)})=N diag(mu)*T. Parameters ---------- T : (M, M) ndarray Transition matrix. n : int Number of steps for chain. mu : (M,) ndarray (optional) Stationary distribution for T. If mu is not specified it will be computed via diagonalization of T. Returns ------- EC : numpy array, shape=(n,n) Expected value for transition counts after a propagation of n steps. """ if n<=0: EC=np.zeros(T.shape) return EC else: if mu is None: mu=statdist(T) EC=n*mu[:, np.newaxis]*T return EC
def correlation_matvec(P, obs1, obs2=None, times=[1]): r"""Time-correlation for equilibrium experiment - via matrix vector products. Parameters ---------- P : (M, M) ndarray Transition matrix obs1 : (M,) ndarray Observable, represented as vector on state space obs2 : (M,) ndarray (optional) Second observable, for cross-correlations times : list of int (optional) List of times (in tau) at which to compute correlation Returns ------- correlations : ndarray Correlation values at given times """ if obs2 is None: obs2=obs1 """Compute stationary vector""" mu=statdist(P) obs1mu=mu*obs1 times=np.asarray(times) """Sort in increasing order""" ind=np.argsort(times) times=times[ind] if times[0]<0: raise ValueError("Times can not be negative") dt=times[1:]-times[0:-1] nt=len(times) correlations=np.zeros(nt) """Propagate obs2 to initial time""" obs2_t=1.0*obs2 obs2_t=propagate(P, obs2_t, times[0]) correlations[0]=np.dot(obs1mu, obs2_t) for i in range(nt-1): obs2_t=propagate(P, obs2_t, dt[i]) correlations[i+1]=np.dot(obs1mu, obs2_t) """Cast back to original order of time points""" correlations=correlations[ind] return correlations
def expectation(P, obs): r"""Equilibrium expectation of given observable. Parameters ---------- P : (M, M) ndarray Transition matrix obs : (M,) ndarray Observable, represented as vector on state space Returns ------- x : float Expectation value """ pi = statdist(P) return np.dot(pi, obs)
def backward_committor(T, A, B): r"""Backward committor between given sets. The backward committor u(x) between sets A and B is the probability for the chain starting in x to have come from A last rather than from B. Parameters ---------- T : (M, M) ndarray Transition matrix A : array_like List of integer state labels for set A B : array_like List of integer state labels for set B Returns ------- u : (M, ) ndarray Vector of forward committor probabilities Notes ----- The forward committor is a solution to the following boundary-value problem .. math:: \sum_j K_{ij} \pi_{j} u_{j}=0 for i in X\(A u B) (I) u_{i}=1 for i \in A (II) u_{i}=0 for i \in B (III) with adjoint of the generator matrix K=(D_pi(P-I))'. """ X = set(range(T.shape[0])) A = set(A) B = set(B) AB = A.intersection(B) notAB = X.difference(A).difference(B) if len(AB) > 0: raise ValueError("Sets A and B have to be disjoint") pi = statdist(T) L = T - eye(T.shape[0], T.shape[0]) D = diags([ pi, ], [ 0, ]) K = (D.dot(L)).T """Assemble left-hand side W for linear system""" """Equation (I)""" W = 1.0 * K """Equation (II)""" W = W.todok() W[list(A), :] = 0.0 W.tocsr() W = W + coo_matrix( (np.ones(len(A)), (list(A), list(A))), shape=W.shape).tocsr() """Equation (III)""" W = W.todok() W[list(B), :] = 0.0 W.tocsr() W = W + coo_matrix( (np.ones(len(B)), (list(B), list(B))), shape=W.shape).tocsr() """Assemble right-hand side r for linear system""" """Equation (I)+(III)""" r = np.zeros(T.shape[0]) """Equation (II)""" r[list(A)] = 1.0 u = spsolve(W, r) return u
def backward_committor(T, A, B, mu=None): r"""Backward committor between given sets. The backward committor u(x) between sets A and B is the probability for the chain starting in x to have come from A last rather than from B. Parameters ---------- T : (M, M) ndarray Transition matrix 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 Returns ------- u : (M, ) ndarray Vector of forward committor probabilities Notes ----- The forward committor is a solution to the following boundary-value problem .. math:: \sum_j K_{ij} \pi_{j} u_{j}=0 for i in X\(A u B) (I) u_{i}=1 for i \in A (II) u_{i}=0 for i \in B (III) with adjoint of the generator matrix K=(D_pi(P-I))'. """ X = set(range(T.shape[0])) A = set(A) B = set(B) AB = A.intersection(B) notAB = X.difference(A).difference(B) if len(AB) > 0: raise ValueError("Sets A and B have to be disjoint") if mu is None: mu = statdist(T) K = np.transpose(mu[:, np.newaxis] * (T - np.eye(T.shape[0]))) """Assemble left-hand side W for linear system""" """Equation (I)""" W = 1.0 * K """Equation (II)""" W[list(A), :] = 0.0 W[list(A), list(A)] = 1.0 """Equation (III)""" W[list(B), :] = 0.0 W[list(B), list(B)] = 1.0 """Assemble right-hand side r for linear system""" """Equation (I)+(III)""" r = np.zeros(T.shape[0]) """Equation (II)""" r[list(A)] = 1.0 u = solve(W, r) return u
def backward_committor(T, A, B): r"""Backward committor between given sets. The backward committor u(x) between sets A and B is the probability for the chain starting in x to have come from A last rather than from B. Parameters ---------- T : (M, M) ndarray Transition matrix A : array_like List of integer state labels for set A B : array_like List of integer state labels for set B Returns ------- u : (M, ) ndarray Vector of forward committor probabilities Notes ----- The forward committor is a solution to the following boundary-value problem .. math:: \sum_j K_{ij} \pi_{j} u_{j}=0 for i in X\(A u B) (I) u_{i}=1 for i \in A (II) u_{i}=0 for i \in B (III) with adjoint of the generator matrix K=(D_pi(P-I))'. """ X = set(range(T.shape[0])) A = set(A) B = set(B) AB = A.intersection(B) notAB = X.difference(A).difference(B) if len(AB) > 0: raise ValueError("Sets A and B have to be disjoint") pi = statdist(T) L = T - eye(T.shape[0], T.shape[0]) D = diags([pi, ], [0, ]) K = (D.dot(L)).T """Assemble left-hand side W for linear system""" """Equation (I)""" W = 1.0 * K """Equation (II)""" W = W.todok() W[list(A), :] = 0.0 W.tocsr() W = W + coo_matrix((np.ones(len(A)), (list(A), list(A))), shape=W.shape).tocsr() """Equation (III)""" W = W.todok() W[list(B), :] = 0.0 W.tocsr() W = W + coo_matrix((np.ones(len(B)), (list(B), list(B))), shape=W.shape).tocsr() """Assemble right-hand side r for linear system""" """Equation (I)+(III)""" r = np.zeros(T.shape[0]) """Equation (II)""" r[list(A)] = 1.0 u = spsolve(W, r) return u
def backward_committor(T, A, B, mu=None): r"""Backward committor between given sets. The backward committor u(x) between sets A and B is the probability for the chain starting in x to have come from A last rather than from B. Parameters ---------- T : (M, M) ndarray Transition matrix 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 Returns ------- u : (M, ) ndarray Vector of forward committor probabilities Notes ----- The forward committor is a solution to the following boundary-value problem .. math:: \sum_j K_{ij} \pi_{j} u_{j}=0 for i in X\(A u B) (I) u_{i}=1 for i \in A (II) u_{i}=0 for i \in B (III) with adjoint of the generator matrix K=(D_pi(P-I))'. """ X=set(range(T.shape[0])) A=set(A) B=set(B) AB=A.intersection(B) notAB=X.difference(A).difference(B) if len(AB)>0: raise ValueError("Sets A and B have to be disjoint") if mu is None: mu=statdist(T) K=np.transpose(mu[:,np.newaxis]*(T-np.eye(T.shape[0]))) """Assemble left-hand side W for linear system""" """Equation (I)""" W=1.0*K """Equation (II)""" W[list(A), :]=0.0 W[list(A), list(A)]=1.0 """Equation (III)""" W[list(B), :]=0.0 W[list(B), list(B)]=1.0 """Assemble right-hand side r for linear system""" """Equation (I)+(III)""" r=np.zeros(T.shape[0]) """Equation (II)""" r[list(A)]=1.0 u=solve(W, r) return u