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) sparse matrix 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 : (M, M) sparse matrix Expected value for transition counts after N steps. """ if(n<=0): EC=coo_matrix(T.shape, dtype=float) return EC else: if mu is None: mu=decomposition.stationary_distribution_from_eigenvector(T) D_mu=diags(mu, 0) EC=n*D_mu.dot(T) return EC
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 test_expected_counts(self): N = 50 T = self.T_sparse p0 = self.mu_sparse EC_n = expected_counts(T, p0, N) D_mu = diags(self.mu_sparse, 0) EC_true = N * D_mu.dot(T) self.assertTrue(sparse_allclose(EC_true, EC_n))
def is_rate_matrix(K, tol): """ True if K is a rate matrix Parameters ---------- K : scipy.sparse matrix Matrix to check tol : float tolerance to check with Returns ------- Truth value : bool True, if K negated diagonal is positive and row sums up to zero. False, otherwise """ K = K.tocsr() # check rows sum up to zero. row_sum = K.sum(axis = 1) sum_eq_zero = np.allclose(row_sum, np.zeros(shape=row_sum.shape), atol=tol) # store copy of original diagonal org_diag = K.diagonal() # substract diagonal K=K-diags(org_diag, 0) # check off diagonals are > 0 values=K.data values_gt_zero = np.allclose(values, np.abs(values), atol = tol) # add diagonal K=K+diags(org_diag, 0) return values_gt_zero and sum_eq_zero
def is_rate_matrix(K, tol): """ True if K is a rate matrix Parameters ---------- K : scipy.sparse matrix Matrix to check tol : float tolerance to check with Returns ------- Truth value : bool True, if K negated diagonal is positive and row sums up to zero. False, otherwise """ K = K.tocsr() # check rows sum up to zero. row_sum = K.sum(axis=1) sum_eq_zero = np.allclose(row_sum, np.zeros(shape=row_sum.shape), atol=tol) # store copy of original diagonal org_diag = K.diagonal() # substract diagonal K = K - diags(org_diag, 0) # check off diagonals are > 0 values = K.data values_gt_zero = np.allclose(values, np.abs(values), atol=tol) # add diagonal K = K + diags(org_diag, 0) return values_gt_zero and sum_eq_zero
def test_expected_counts_stationary(self): n = 50 T = self.T_sparse mu = self.mu_sparse D_mu = diags(self.mu_sparse, 0) EC_true = n * D_mu.dot(T) """Compute mu on the fly""" EC_n = expected_counts_stationary(T, n) self.assertTrue(sparse_allclose(EC_true, EC_n)) """With precomputed mu""" EC_n = expected_counts_stationary(T, n, mu=mu) self.assertTrue(sparse_allclose(EC_true, EC_n)) n = 0 EC_true = scipy.sparse.coo_matrix(T.shape) EC_n = expected_counts_stationary(T, n) self.assertTrue(sparse_allclose(EC_true, EC_n))
def expected_counts(p0, T, N): r"""Compute expected transition counts for Markov chain after N steps. Expected counts are computed according to ..math:: E[C_{ij}^{(n)}]=\sum_{k=0}^{N-1} (p_0^T T^{k})_{i} p_{ij} Parameters ---------- p0 : (M,) ndarray Starting (probability) vector of the chain. T : (M, M) sparse matrix Transition matrix of the chain. N : int Number of steps to take from initial state. Returns -------- EC : (M, M) sparse matrix Expected value for transition counts after N steps. """ if(N<=0): EC=coo_matrix(T.shape, dtype=float) return EC else: """Probability vector after (k=0) propagations""" p_k=1.0*p0 """Sum of vectors after (k=0) propagations""" p_sum=1.0*p_k """Transpose T to use sparse dot product""" Tt=T.transpose() for k in np.arange(N-1): """Propagate one step p_{k} -> p_{k+1}""" p_k=Tt.dot(p_k) """Update sum""" p_sum+=p_k D_psum=diags(p_sum, 0) EC=D_psum.dot(T) return EC