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_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)
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_bickley_integrate(vectorized_ivp, full_periodic): X = np.vstack((np.full((5, ), 0.1), np.linspace(-2.9, 2.9, num=5))).T simulator = dt.data.BickleyJet(1e-4, 10000, full_periodic=full_periodic) assert_(simulator.periodic_bc) simulator_back = dt.data.BickleyJet(-1e-4, 10000, full_periodic=full_periodic) with assert_raises(RuntimeError) if full_periodic else nullcontext(): simulator.periodic_bc = False assert_(not simulator.periodic_bc) with assert_raises(RuntimeError) if full_periodic else nullcontext(): simulator_back.periodic_bc = False assert_(not simulator_back.periodic_bc) time, traj = simulator.trajectory(0, X, 11, return_time=True) Xfinal = traj[:, -1] time_back, traj_back = simulator_back.trajectory(10, traj[:, -1], 11, return_time=True) assert_array_almost_equal(time, np.flip(time_back, axis=1)) assert_array_almost_equal(traj, np.flip(traj_back, axis=1)) t_eval = np.linspace(0, 10, num=11, endpoint=True) periodic_traj_back = traj_back if full_periodic else dt.data.BickleyJet.apply_periodic_boundary_conditions( traj_back) if not full_periodic: periodic_traj = dt.data.BickleyJet.apply_periodic_boundary_conditions( traj, inplace=False) else: periodic_traj = traj assert_( np.all((periodic_traj[..., 0] <= 20) & (periodic_traj[..., 0] >= 0))) # inside domain for i in range(5): assert_equal(t_eval, time[i]) soln = solve_ivp(simulator.f, [0, 10], y0=X[i], vectorized=vectorized_ivp, method='RK45', atol=1e-12, rtol=1e-12, t_eval=t_eval) solnpbc = dt.data.BickleyJet.apply_periodic_boundary_conditions( soln.y.T, inplace=False) assert_array_almost_equal(solnpbc, periodic_traj[i]) soln_bwd = solve_ivp(simulator.f, [10, 0], y0=Xfinal[i], vectorized=vectorized_ivp, method='RK45', atol=1e-12, rtol=1e-12, t_eval=t_eval[::-1]) soln_bwdpbc = dt.data.BickleyJet.apply_periodic_boundary_conditions( soln_bwd.y.T, inplace=False) assert_array_almost_equal(soln_bwdpbc, periodic_traj_back[i], decimal=5) assert_array_almost_equal(periodic_traj_back[i, -1], X[i]) assert_array_almost_equal(soln_bwdpbc[-1], X[i], decimal=5)