def test_rdl_decomposition(scenario, ncv_values, norm, statdist, reversible): k, bdc = scenario dim = bdc.q.shape[0] P = bdc.transition_matrix mu = bdc.stationary_distribution with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): Rn, Dn, Ln = rdl_decomposition(P, reversible=reversible, norm=norm, ncv=ncv_values, k=k, mu=mu if statdist else None) Xn = Ln @ Rn """Right-eigenvectors""" assert_allclose(P @ Rn, Rn @ Dn) """Left-eigenvectors""" assert_allclose(Ln @ P, Dn @ Ln) """Orthonormality""" assert_allclose(Xn, np.eye(dim if k is None else k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) if norm == 'standard' and reversible: """Standard l2-normalization of right eigenvectors except dominant one""" Yn = Rn.T @ Rn assert_allclose(np.diag(Yn)[1:], 1.0) if norm == 'reversible': """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
def test_eigenvalues(scenario, ncv_values): k, bdc = scenario P = bdc.transition_matrix ev = eigvals(P) """Sort with decreasing magnitude""" ev = ev[np.argsort(np.abs(ev))[::-1]] """k=None""" with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): evn = eigenvalues(P, ncv=ncv_values, k=k) assert_allclose(ev[:k], evn)
def test_timescales(scenario, ncv_values, tau, statdist, reversible): k, bdc = scenario P = bdc.transition_matrix mu = bdc.stationary_distribution ev = eigvals(P) """Sort with decreasing magnitude""" ev = ev[np.argsort(np.abs(ev))[::-1]] ts = -1.0 / np.log(np.abs(ev)) with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): tsn = timescales(P, k=k, tau=tau, mu=mu if statdist else None, reversible=reversible) assert_allclose(tau * ts[1:k], tsn[1:k])
def test_eigenvalues_reversible(scenario, ncv_values): k, bdc = scenario P = bdc.transition_matrix ev = eigvals(P) """Sort with decreasing magnitude""" ev = ev[np.argsort(np.abs(ev))[::-1]] with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): """reversible without given mu""" evn = eigenvalues(P, reversible=True, k=k, ncv=ncv_values) assert_allclose(ev[:k], evn) """reversible with given mu""" evn = eigenvalues(P, reversible=True, mu=bdc.stationary_distribution, k=k, ncv=ncv_values) assert_allclose(ev[:k], evn)
def test_eigenvectors(scenario, ncv_values): k, bdc = scenario P = bdc.transition_matrix ev = eigvals(P) ev = ev[np.argsort(np.abs(ev))[::-1]] Dn = np.diag(ev) Dnk = Dn[:, :k][:k, :] with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): # right eigenvectors Rn = eigenvectors(P, k=k, ncv=ncv_values) assert_allclose(P @ Rn, Rn @ Dnk) # left eigenvectors Ln = eigenvectors(P, right=False, k=k, ncv=ncv_values).T assert_allclose(Ln.T @ P, Dnk @ Ln.T) # orthogonality Xn = Ln.T @ Rn di = np.diag_indices(Xn.shape[0] if k is None else k) Xn[di] = 0.0 assert_allclose(Xn, 0)
def test_eigenvectors_reversible(scenario, ncv_values): k, bdc = scenario P = bdc.transition_matrix ev = eigvals(P) ev = ev[np.argsort(np.abs(ev))[::-1]] Dn = np.diag(ev) Dnk = Dn[:, :k][:k, :] with assert_raises( ValueError) if bdc.sparse and k is None else nullcontext(): # right eigenvectors Rn = eigenvectors(P, k=k, reversible=True, ncv=ncv_values) assert_allclose(P @ Rn, Rn @ Dnk) # left eigenvectors Ln = eigenvectors(P, right=False, k=k, reversible=True, ncv=ncv_values).T assert_allclose(Ln.T @ P, Dnk @ Ln.T) # orthogonality Xn = Ln.T @ Rn di = np.diag_indices(Xn.shape[0] if k is None else k) Xn[di] = 0.0 assert_allclose(Xn, 0) Rn = eigenvectors(P, k=k, ncv=ncv_values, reversible=True, mu=bdc.stationary_distribution) assert_allclose(ev[:k][np.newaxis, :] * Rn, P.dot(Rn)) Ln = eigenvectors(P, right=False, k=k, ncv=ncv_values, reversible=True, mu=bdc.stationary_distribution).T assert_allclose(P.transpose().dot(Ln), ev[:k][np.newaxis, :] * Ln)