def test_markovchain_pmatrices(): """ Test the methods of MarkovChain, as well as mc_compute_stationary, with P matrix and known solutions """ # Matrix with two recurrent classes [0, 1] and [3, 4, 5], # which have periods 2 and 3, respectively Q = np.zeros((6, 6)) Q[0, 1], Q[1, 0] = 1, 1 Q[2, [0, 3]] = 1 / 2 Q[3, 4], Q[4, 5], Q[5, 3] = 1, 1, 1 Q_stationary_dists = \ np.array([[1/2, 1/2, 0, 0, 0, 0], [0, 0, 0, 1/3, 1/3, 1/3]]) testset = [ { 'P': np.array([[0.4, 0.6], [0.2, 0.8]]), # P matrix 'stationary_dists': np.array([[0.25, 0.75]]), # Known solution 'comm_classes': [np.arange(2)], 'rec_classes': [np.arange(2)], 'is_irreducible': True, 'period': 1, 'is_aperiodic': True, 'cyclic_classes': [np.arange(2)], }, { 'P': sparse.csr_matrix([[0.4, 0.6], [0.2, 0.8]]), 'stationary_dists': np.array([[0.25, 0.75]]), 'comm_classes': [np.arange(2)], 'rec_classes': [np.arange(2)], 'is_irreducible': True, 'period': 1, 'is_aperiodic': True, 'cyclic_classes': [np.arange(2)], }, { 'P': np.array([[0, 1], [1, 0]]), 'stationary_dists': np.array([[0.5, 0.5]]), 'comm_classes': [np.arange(2)], 'rec_classes': [np.arange(2)], 'is_irreducible': True, 'period': 2, 'is_aperiodic': False, 'cyclic_classes': [np.array([0]), np.array([1])], }, { 'P': np.eye(2), 'stationary_dists': np.array([[1, 0], [0, 1]]), 'comm_classes': [np.array([0]), np.array([1])], 'rec_classes': [np.array([0]), np.array([1])], 'is_irreducible': False, 'period': 1, 'is_aperiodic': True, }, # Reducible mc with a unique recurrent class, # where n-1 is a transient state { 'P': np.array([[1, 0], [1, 0]]), 'stationary_dists': np.array([[1, 0]]), 'comm_classes': [np.array([0]), np.array([1])], 'rec_classes': [np.array([0])], 'is_irreducible': False, 'period': 1, 'is_aperiodic': True, }, { 'P': Q, 'stationary_dists': Q_stationary_dists, 'comm_classes': [np.array([0, 1]), np.array([2]), np.array([3, 4, 5])], 'rec_classes': [np.array([0, 1]), np.array([3, 4, 5])], 'is_irreducible': False, 'period': 6, 'is_aperiodic': False, }, { 'P': sparse.csr_matrix(Q), 'stationary_dists': Q_stationary_dists, 'comm_classes': [np.array([0, 1]), np.array([2]), np.array([3, 4, 5])], 'rec_classes': [np.array([0, 1]), np.array([3, 4, 5])], 'is_irreducible': False, 'period': 6, 'is_aperiodic': False, } ] # Loop Through TestSet # for test_dict in testset: mc = MarkovChain(test_dict['P']) computed = mc.stationary_distributions assert_allclose(computed, test_dict['stationary_dists']) assert (mc.num_communication_classes == len(test_dict['comm_classes'])) assert (mc.is_irreducible == test_dict['is_irreducible']) assert (mc.num_recurrent_classes == len(test_dict['rec_classes'])) list_of_array_equal( sorted(mc.communication_classes, key=lambda x: x[0]), sorted(test_dict['comm_classes'], key=lambda x: x[0])) list_of_array_equal( sorted(mc.recurrent_classes, key=lambda x: x[0]), sorted(test_dict['rec_classes'], key=lambda x: x[0])) assert (mc.period == test_dict['period']) assert (mc.is_aperiodic == test_dict['is_aperiodic']) try: list_of_array_equal( sorted(mc.cyclic_classes, key=lambda x: x[0]), sorted(test_dict['cyclic_classes'], key=lambda x: x[0])) except NotImplementedError: assert (mc.is_irreducible is False) # Test of mc_compute_stationary computed = mc_compute_stationary(test_dict['P']) assert_allclose(computed, test_dict['stationary_dists'])
def test_markovchain_pmatrices(): """ Test the methods of MarkovChain, as well as mc_compute_stationary, with P matrix and known solutions """ # Matrix with two recurrent classes [0, 1] and [3, 4, 5], # which have periods 2 and 3, respectively Q = np.zeros((6, 6)) Q[0, 1], Q[1, 0] = 1, 1 Q[2, [0, 3]] = 1/2 Q[3, 4], Q[4, 5], Q[5, 3] = 1, 1, 1 Q_stationary_dists = \ np.array([[1/2, 1/2, 0, 0, 0, 0], [0, 0, 0, 1/3, 1/3, 1/3]]) testset = [ {'P': np.array([[0.4, 0.6], [0.2, 0.8]]), # P matrix 'stationary_dists': np.array([[0.25, 0.75]]), # Known solution 'comm_classes': [np.arange(2)], 'rec_classes': [np.arange(2)], 'is_irreducible': True, 'period': 1, 'is_aperiodic': True, 'cyclic_classes': [np.arange(2)], }, {'P': np.array([[0, 1], [1, 0]]), 'stationary_dists': np.array([[0.5, 0.5]]), 'comm_classes': [np.arange(2)], 'rec_classes': [np.arange(2)], 'is_irreducible': True, 'period': 2, 'is_aperiodic': False, 'cyclic_classes': [np.array([0]), np.array([1])], }, {'P': np.eye(2), 'stationary_dists': np.array([[1, 0], [0, 1]]), 'comm_classes': [np.array([0]), np.array([1])], 'rec_classes': [np.array([0]), np.array([1])], 'is_irreducible': False, 'period': 1, 'is_aperiodic': True, }, # Reducible mc with a unique recurrent class, # where n-1 is a transient state {'P': np.array([[1, 0], [1, 0]]), 'stationary_dists': np.array([[1, 0]]), 'comm_classes': [np.array([0]), np.array([1])], 'rec_classes': [np.array([0])], 'is_irreducible': False, 'period': 1, 'is_aperiodic': True, }, {'P': Q, 'stationary_dists': Q_stationary_dists, 'comm_classes': [np.array([0, 1]), np.array([2]), np.array([3, 4, 5])], 'rec_classes': [np.array([0, 1]), np.array([3, 4, 5])], 'is_irreducible': False, 'period': 6, 'is_aperiodic': False, } ] # Loop Through TestSet # for test_dict in testset: mc = MarkovChain(test_dict['P']) computed = mc.stationary_distributions assert_allclose(computed, test_dict['stationary_dists']) assert(mc.num_communication_classes == len(test_dict['comm_classes'])) assert(mc.is_irreducible == test_dict['is_irreducible']) assert(mc.num_recurrent_classes == len(test_dict['rec_classes'])) list_of_array_equal( sorted(mc.communication_classes, key=lambda x: x[0]), sorted(test_dict['comm_classes'], key=lambda x: x[0]) ) list_of_array_equal( sorted(mc.recurrent_classes, key=lambda x: x[0]), sorted(test_dict['rec_classes'], key=lambda x: x[0]) ) assert(mc.period == test_dict['period']) assert(mc.is_aperiodic == test_dict['is_aperiodic']) try: list_of_array_equal( sorted(mc.cyclic_classes, key=lambda x: x[0]), sorted(test_dict['cyclic_classes'], key=lambda x: x[0]) ) except NotImplementedError: assert(mc.is_irreducible is False) # Test of mc_compute_stationary computed = mc_compute_stationary(test_dict['P']) assert_allclose(computed, test_dict['stationary_dists'])