def test_opt_soft_nelder_mead_mu0(self, svecs_mu0: np.ndarray, A_mu0: np.ndarray): A, chi, fopt = _opt_soft(svecs_mu0, A_mu0) crispness = np.true_divide(3 - fopt, 3) assert_allclose(crispness, 0.973, atol=1e-3)
def test_P_2_LR( self, P_2: np.ndarray, minChi_P_2_LR: np.ndarray, crispness_values_P_2_LR: np.ndarray, optimal_crispness_P_2_LR: np.float64, n_m_P_2_LR: np.int64, top_eigenvalues_P_2_LR: np.ndarray, method: str, ): if method == "krylov": pytest.importorskip("mpi4py") pytest.importorskip("petsc4py") pytest.importorskip("slepc4py") g = GPCCA(P_2, eta=None, z="LR", method=method) # The following very crude minChi testing is necessary, # since the initial guess for the rotation matrix and thus minChi can vary. minChi = g.minChi(2, 12) assert len(minChi) == len(minChi_P_2_LR) assert minChi[0] > -1e-08 assert minChi[1] > -1e-08 assert minChi[3] > -1e-01 assert minChi[10] > -1e-08 g.optimize({"m_min": 2, "m_max": 12}) n_m = g.n_m assert_allclose(g.crispness_values, crispness_values_P_2_LR) assert_allclose(g.optimal_crispness, optimal_crispness_P_2_LR) assert_allclose(n_m, n_m_P_2_LR) assert_allclose(g.top_eigenvalues, top_eigenvalues_P_2_LR) assert_allclose(g.dominant_eigenvalues, top_eigenvalues_P_2_LR[:n_m])
def test_opt_soft_nelder_mead_mu1000(self, svecs_mu1000: np.ndarray, A_mu1000: np.ndarray): A, chi, fopt = _opt_soft(svecs_mu1000, A_mu1000) crispness = np.true_divide(5 - fopt, 5) assert_allclose(crispness, 0.804, atol=0.0025)
def test_coarse_grain_sparse_eq_dense(self, example_matrix_mu: np.ndarray): P, sd = get_known_input(example_matrix_mu) Pc_b = gpcca_coarsegrain(P, m=3, eta=sd, method="brandts") Pc_k = gpcca_coarsegrain(csr_matrix(P), m=3, eta=sd, method="krylov") assert_allclose(Pc_k, Pc_b)
def test_stat_dist_regression(self, P: np.ndarray, P_mu: np.ndarray, sparse: bool): if sparse: P = csr_matrix(P) else: assert not issparse(P) mu_actual = stationary_distribution(P) assert_allclose(P_mu, mu_actual)
def test_gram_schmidt_mod_R2(self): Q = _gram_schmidt_mod(np.array([[3, 1], [2, 2]], dtype=np.float64), np.array([0.5, 0.5])) s = np.sqrt(0.5) orthosys = np.array([[s, -s], [s, s]]) assert_allclose(Q, orthosys)
def test_coarse_grain_sparse(self, P: np.ndarray, sd: np.ndarray, count_Pc: np.ndarray): Pc = gpcca_coarsegrain(csr_matrix(P), m=(2, 10), eta=sd, method="krylov") assert_allclose(Pc.sum(1), 1.0) assert_allclose(Pc, count_Pc, atol=eps)
def test_gpcca_krylov_sparse_eq_dense_mu(self, example_matrix_mu: np.ndarray): mu = int(example_matrix_mu[2, 4]) if mu == 1000: pytest.skip("rtol=0.03359514, atol=3.73976903e+14") opt_clust = {0: 3, 10: 3, 50: 3, 100: 3, 200: 2, 500: 2, 1000: 5}[mu] P, sd = get_known_input(example_matrix_mu) g_s = GPCCA(csr_matrix(P), eta=sd, method="krylov").optimize(opt_clust) g_d = GPCCA(P, eta=sd, method="krylov").optimize(opt_clust) g_b = GPCCA(P, eta=sd, method="brandts").optimize(opt_clust) assert issparse(g_s.transition_matrix) assert not issparse(g_d.transition_matrix) assert not issparse(g_b.transition_matrix) assert_allclose(g_s.memberships.sum(1), 1.0) assert_allclose(g_d.memberships.sum(1), 1.0) assert_allclose(g_b.memberships.sum(1), 1.0) X_k, X_kd, X_b = g_s.schur_vectors, g_d.schur_vectors, g_b.schur_vectors RR_k, RR_kd, RR_b = g_s.schur_matrix, g_d.schur_matrix, g_b.schur_matrix # check if it's a correct Schur form _assert_schur(P, X_k, RR_k, N=None) _assert_schur(P, X_kd, RR_kd, N=None) _assert_schur(P, X_b, RR_b, N=None) # check if they span the same subspace assert np.max(subspace_angles(X_k, X_kd)) < eps assert np.max(subspace_angles(X_kd, X_b)) < eps ms, md, mb = g_s.memberships, g_d.memberships, g_b.memberships cs, cd, cb = ( g_s.coarse_grained_transition_matrix, g_d.coarse_grained_transition_matrix, g_b.coarse_grained_transition_matrix, ) for left, right in combinations( ["brandts", "dense_krylov", "sparse_krylov"], r=2): ml, cl = locals()[f"m{left[0]}"], locals()[f"c{left[0]}"] mr, cr = locals()[f"m{right[0]}"], locals()[f"c{right[0]}"] perm = _find_permutation(ml, mr) mr = mr[:, perm] assert_allclose(mr, ml, atol=1e-4) cr = cr[perm, :][:, perm] try: assert_allclose(cr, cl, atol=1e-4) except AssertionError as e: raise RuntimeError(f"Comparing: {left} and {right}.") from e
def test_init_final_rot_matrix_krylov_dense( self, svecs_mu0_krylov_dense: np.ndarray, A_mu0_krylov_dense_init: np.ndarray, A_mu0_krylov_dense: np.ndarray, ): init_rot = _initialize_rot_matrix(svecs_mu0_krylov_dense) _, final_rot, _ = _gpcca_core(svecs_mu0_krylov_dense) assert_allclose(init_rot, A_mu0_krylov_dense_init) assert_allclose(final_rot, A_mu0_krylov_dense)
def test_initialize_A(self): mu0 = mu(0) P, sd = get_known_input(mu0) X, _, _ = _do_schur(P, sd, m=4) evs = X[:, :4] A = _initialize_rot_matrix(evs) index = _indexsearch(evs) A_exp = pinv(X[index, :4]) assert_allclose(A, A_exp)
def test_init_final_rot_matrix_brandts( self, svecs_mu0: np.ndarray, A_mu0_init: np.ndarray, A_mu0: np.ndarray, ): init_rot = _initialize_rot_matrix(svecs_mu0) _, final_rot, _ = _gpcca_core(svecs_mu0) assert_allclose(init_rot, A_mu0_init) assert_allclose(final_rot, A_mu0)
def test_cluster_by_isa(self, chi_isa_mu0_n3: np.ndarray, chi_isa_mu100_n3: np.ndarray): # chi_sa_mu0_n3 has permuted 2nd and 3d columns when compared to the matlab version for mu_, chi_exp in zip([0, 100], [chi_isa_mu0_n3, chi_isa_mu100_n3]): P, sd = get_known_input(mu(mu_)) X, _, _ = _do_schur(P, sd, m=3) chi, _ = _cluster_by_isa(X[:, :3]) chi = chi[:, _find_permutation(chi_exp, chi)] assert_allclose(chi.T @ chi, chi_exp.T @ chi_exp) assert_allclose(chi, chi_exp)
def test_objective_2(self, svecs_mu1000: np.ndarray, A_mu1000_init: np.ndarray, A_mu1000: np.ndarray): k = 5 alpha = np.zeros((k - 1)**2) for i in range(k - 1): for j in range(k - 1): alpha[j + i * (k - 1)] = A_mu1000_init[i + 1, j + 1] act_val = _objective(alpha, svecs_mu1000) exp_val = k - np.sum( np.true_divide(np.sum(A_mu1000**2, axis=0), A_mu1000[0, :])) assert_allclose(act_val, exp_val)
def test_eigendecomposition_slepsc_regression( self, test_matrix_1: np.ndarray, test_matrix_1_eigenvalues: np.ndarray, test_matrix_1_eigenvectors: np.ndarray, test_matrix_2: np.ndarray, test_matrix_2_eigenvalues: np.ndarray, test_matrix_2_eigenvectors: np.ndarray, ): eigs_1, vecs_1 = _eigs_slepc(csr_matrix(test_matrix_1), k=11) assert_allclose( test_matrix_1_eigenvalues, eigs_1, ) assert_allclose(subspace_angles(test_matrix_1_eigenvectors, vecs_1), 0.0, atol=1e-6, rtol=1e-5) eigs_2, vecs_2 = _eigs_slepc(csr_matrix(test_matrix_2), k=13) assert_allclose(test_matrix_2_eigenvalues, eigs_2) assert_allclose(subspace_angles(test_matrix_2_eigenvectors, vecs_2), 0.0, atol=1e-6, rtol=1e-5)
def test_P_i(self, P_i: np.ndarray, method: str): if method == "krylov": pytest.importorskip("mpi4py") pytest.importorskip("petsc4py") pytest.importorskip("slepc4py") g = GPCCA(P_i, eta=None, method=method) for m in range(2, 8): try: g.optimize(m) except ValueError: continue X, RR = g.schur_vectors, g.schur_matrix assert_allclose(g.memberships.sum(1), 1.0) assert_allclose(g.coarse_grained_transition_matrix.sum(1), 1.0) assert_allclose(g.coarse_grained_input_distribution.sum(), 1.0) if g.coarse_grained_stationary_probability is not None: assert_allclose(g.coarse_grained_stationary_probability.sum(), 1.0) np.testing.assert_allclose(X[:, 0], 1.0) assert np.max(subspace_angles(P_i @ X, X @ RR)) < eps
def test_gpcca_krylov_sparse_eq_dense_count(self, P: np.ndarray, sd: np.ndarray): # all of them cluster optimally into 3 clusters g_s = GPCCA(csr_matrix(P), eta=sd, method="krylov").optimize([2, 5]) g_d = GPCCA(P, eta=sd, method="krylov").optimize([2, 5]) g_b = GPCCA(P, eta=sd, method="brandts").optimize([2, 5]) assert issparse(g_s.transition_matrix) assert not issparse(g_d.transition_matrix) assert not issparse(g_b.transition_matrix) assert_allclose(g_s.memberships.sum(1), 1.0) assert_allclose(g_d.memberships.sum(1), 1.0) assert_allclose(g_b.memberships.sum(1), 1.0) X_k, X_kd, X_b = g_s.schur_vectors, g_d.schur_vectors, g_b.schur_vectors RR_k, RR_kd, RR_b = g_s.schur_matrix, g_d.schur_matrix, g_b.schur_matrix # check if it's a correct Schur form _assert_schur(P, X_k, RR_k, N=None, subspace=True) _assert_schur(P, X_kd, RR_kd, N=None, subspace=True) _assert_schur(P, X_b, RR_b, N=None, subspace=True) # check if they span the same subspace assert np.max(subspace_angles(X_k, X_kd)) < eps assert np.max(subspace_angles(X_kd, X_b)) < eps ms, md, mb = g_s.memberships, g_d.memberships, g_b.memberships cs, cd, cb = ( g_s.coarse_grained_transition_matrix, g_d.coarse_grained_transition_matrix, g_b.coarse_grained_transition_matrix, ) for left, right in combinations( ["brandts", "dense_krylov", "sparse_krylov"], r=2): ml, cl = locals()[f"m{left[0]}"], locals()[f"c{left[0]}"] mr, cr = locals()[f"m{right[0]}"], locals()[f"c{right[0]}"] perm = _find_permutation(ml, mr) mr = mr[:, perm] assert_allclose(mr, ml) cr = cr[perm, :][:, perm] try: assert_allclose(cr, cl) except AssertionError as e: raise RuntimeError(f"Comparing: {left} and {right}.") from e
def test_gram_schmidt_mod_R4(self): Q = _gram_schmidt_mod( np.array([[1, 1, 1, 1], [-1, 4, 4, 1], [4, -2, 2, 0]], dtype=np.float64).T, np.array([0.25, 0.25, 0.25, 0.25]), ) d = np.true_divide s2 = np.sqrt(2) s3 = np.sqrt(3) u1 = np.array([0.5] * 4) u2 = np.array([d(-1, s2), d(s2, 3), d(s2, 3), d(-1, 3 * s2)]) u3 = np.array( [d(1, 2 * s3), d(-5, 6 * s3), d(7, 6 * s3), d(-5, 6 * s3)]) orthosys = np.array([u1, u2, u3]).T assert_allclose(Q, orthosys)
def test_stat_dist_regression_test_matrices( self, test_matrix_1: np.ndarray, test_matrix_1_stationary_distribution, test_matrix_2: np.ndarray, test_matrix_2_stationary_distribution, test_matrix_3: np.ndarray, ): # For the first two matrices, the stationary distribution exists and is unique assert_allclose( test_matrix_1_stationary_distribution, stationary_distribution(test_matrix_1), ) assert_allclose(test_matrix_2_stationary_distribution, stationary_distribution(test_matrix_2)) # For the third matrix, the stationary distribution is not uniquely defined # Note: we currently only check irreducibility for sparse matrices if not issparse(test_matrix_3): test_matrix_3 = csr_matrix(test_matrix_3) with pytest.raises(ValueError, match=r"This matrix is reducible."): stationary_distribution(test_matrix_3)
def _assert_schur( P: np.ndarray, X: np.ndarray, RR: np.ndarray, N: Optional[int] = None, subspace: bool = False, ): if N is not None: np.testing.assert_array_equal(P.shape, [N, N]) np.testing.assert_array_equal(X.shape, [N, N]) np.testing.assert_array_equal(RR.shape, [N, N]) if subspace: assert_allclose(subspace_angles(P @ X, X @ RR), 0.0, atol=1e-6, rtol=1e-5) else: assert np.all(np.abs(X @ RR - P @ X) < eps), np.abs(X @ RR - P @ X).max() assert np.all(np.abs(X[:, 0] - 1) < eps), np.abs(X[:, 0]).max()
def test_normal_case( self, P: np.ndarray, sd: np.ndarray, count_sd: np.ndarray, count_Pc: np.ndarray, count_chi: np.ndarray, ): assert_allclose(sd, count_sd) g = GPCCA(P, eta=sd) g.optimize((2, 10)) Pc = g.coarse_grained_transition_matrix assert_allclose(Pc, count_Pc, atol=eps) assert_allclose(Pc.sum(1), 1.0) assert_allclose(g.coarse_grained_transition_matrix.sum(1), 1.0) assert_allclose(g.memberships.sum(1), 1.0) assert np.max(subspace_angles(g.memberships, count_chi)) < eps
def test_sort_real_schur(self, R_i: np.ndarray): def sort_evals(e: np.ndarray, take: int = 4) -> np.ndarray: return e[np.argsort(np.linalg.norm(np.c_[e.real, e.imag], axis=1))][:take] # test_SRSchur_num_t Q = np.eye(4) QQ, RR, ap = sort_real_schur(Q, R_i, z="LM", b=0) assert np.all(np.array(ap) <= 1), ap EQ = np.true_divide(np.linalg.norm(Q - QQ.T @ QQ, ord=1), eps) assert_allclose(EQ, 1.0, atol=5) EA = np.true_divide( np.linalg.norm(R_i - QQ @ RR @ QQ.T, ord=1), eps * np.linalg.norm(R_i, ord=1), ) assert_allclose(EA, 1.0, atol=5) l1 = sort_evals(eigvals(R_i)) l2 = sort_evals(eigvals(RR)) EL = np.true_divide(np.abs(l1 - l2), eps * np.abs(l1)) assert_allclose(EL, 1.0, atol=5)
def test_memberships_normal_case_sparse_vs_dense( self, P: np.ndarray, sd: np.ndarray, count_sd: np.ndarray, ): assert_allclose(sd, count_sd) # sanity check g_d = GPCCA(P, eta=sd) g_d.optimize((2, 10)) g_s = GPCCA(csr_matrix(P), eta=sd, method="krylov") g_s.optimize((2, 10)) # also passes without this ms, md = g_s.memberships, g_d.memberships cs, cd = ( g_s.coarse_grained_transition_matrix, g_d.coarse_grained_transition_matrix, ) perm = _find_permutation(md, ms) ms = ms[:, perm] assert_allclose(ms, md) cs = cs[perm, :][:, perm] assert_allclose(cs, cd)
def test_stat_dist_sparse_dense(self, sparse: bool): q, p = _create_qp(100) P, mu_expected = bdc(q=q, p=p, sparse=sparse) mu_actual = stationary_distribution(P) assert_allclose(mu_expected, mu_actual)
def test_stat_dist_iteration(self, dim: int): q, p = _create_qp(dim) P, mu_expected = bdc(q=q, p=p, sparse=False) mu_actual = stationary_distribution_from_backward_iteration(P) assert_allclose(mu_expected, mu_actual)
def test_stat_dist_decomposition(self, dim: int): q, p = _create_qp(dim) P, mu_expected = bdc(q=q, p=p, sparse=False) mu_actual = stationary_distribution_from_eigenvector(P) assert_allclose(mu_expected, mu_actual)
def test_normal_case_sparse( self, P: np.ndarray, sd: np.ndarray, count_sd: np.ndarray, count_Pc: np.ndarray, count_chi: np.ndarray, count_chi_sparse: np.ndarray, ): assert_allclose(sd, count_sd) g = GPCCA(csr_matrix(P), eta=sd, method="krylov") g.optimize((2, 10)) Pc = g.coarse_grained_transition_matrix assert_allclose(Pc, count_Pc, atol=eps) assert_allclose(Pc.sum(1), 1.0) assert_allclose(g.coarse_grained_transition_matrix.sum(1), 1.0) assert_allclose(g.memberships.sum(1), 1.0) # regenerated ground truth memberships chi = g.memberships chi = chi[:, _find_permutation(count_chi_sparse, chi)] assert_allclose(chi, count_chi_sparse, atol=eps) # ground truth memberships from matlab chi = chi[:, _find_permutation(count_chi, chi)] assert np.max(np.abs(chi - count_chi)) < 1e-4