def test_DiscreteMarkovChain_point(): test_Gammas = at.as_tensor_variable(np.array([[[1.0, 0.0], [0.0, 1.0]]])) with pm.Model(): # XXX: `draw_values` won't use the `Deterministic`s values in the `point` map! # Also, `Constant` is only for integer types (?!), so we can't use that. test_gamma_0 = pm.Dirichlet("gamma_0", np.r_[1.0, 1000.0], shape=2) test_point = {"gamma_0": np.r_[1.0, 0.0]} assert np.all( DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=10).random(point=test_point) == 0) assert np.all( DiscreteMarkovChain.dist(test_Gammas, 1.0 - test_gamma_0, shape=10).random( point=test_point) == 1)
def test_DiscreteMarkovChain_logp(Gammas, gamma_0, obs, exp_res): aesara.config.compute_test_value = "warn" test_dist = DiscreteMarkovChain.dist(Gammas, gamma_0, shape=obs.shape[-1]) test_logp_tt = test_dist.logp(obs) test_logp_val = test_logp_tt.eval() if exp_res is None: def logp_single_chain(Gammas, gamma_0, obs): state_transitions = np.stack([obs[:-1], obs[1:]]).T p_S_0_to_1 = gamma_0.dot(Gammas[0]) p_S_obs = np.empty_like(obs, dtype=np.float64) p_S_obs[0] = p_S_0_to_1[obs[0]] for t, (S_tm1, S_t) in enumerate(state_transitions): p_S_obs[t + 1] = Gammas[t, S_tm1, S_t] return np.log(p_S_obs) logp_fn = np.vectorize(logp_single_chain, signature="(n,m,m),(m),(n)->(n)") Gammas = np.broadcast_to(Gammas, (obs.shape[0], ) + Gammas.shape[-2:]) exp_res = logp_fn(Gammas, gamma_0, obs) exp_res = exp_res.sum(-1) assert np.allclose(test_logp_val, exp_res)
def test_DiscreteMarkovChain_random(): # A single transition matrix and initial probabilities vector for each # element in the state sequence test_Gamma = np.array([[[1.0, 0.0], [0.0, 1.0]]]) test_gamma_0 = np.r_[0.0, 1.0] test_sample = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=10).random() assert np.all(test_sample == 1) test_sample = DiscreteMarkovChain.dist(test_Gamma, 1.0 - test_gamma_0, shape=10).random() assert np.all(test_sample == 0) test_sample = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=10).random(size=12) assert test_sample.shape == ( 12, 10, ) test_sample = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=10).random(size=2) assert np.array_equal(test_sample, np.stack([np.ones(10), np.ones(10)], 0).astype(int)) # Now, the same set-up, but--this time--generate two state sequences # samples test_Gamma = np.array([[[0.8, 0.2], [0.2, 0.8]]]) test_gamma_0 = np.r_[0.2, 0.8] test_sample = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=10).random(size=2) # TODO: Fix the seed, and make sure there's at least one 0 and 1? assert test_sample.shape == (2, 10) # Two transition matrices--for two distinct state sequences--and one vector # of initial probs. test_Gamma = np.stack([ np.array([[[1.0, 0.0], [0.0, 1.0]]]), np.array([[[1.0, 0.0], [0.0, 1.0]]]) ]) test_gamma_0 = np.r_[0.0, 1.0] test_dist = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=(2, 10)) test_sample = test_dist.random() assert np.array_equal(test_sample, np.stack([np.ones(10), np.ones(10)], 0).astype(int)) assert test_sample.shape == (2, 10) # Now, the same set-up, but--this time--generate three state sequence # samples test_sample = test_dist.random(size=3) assert np.array_equal( test_sample, np.tile( np.stack([np.ones(10), np.ones(10)], 0).astype(int), (3, 1, 1)), ) assert test_sample.shape == (3, 2, 10) # Two transition matrices and initial probs. for two distinct state # sequences test_Gamma = np.stack([ np.array([[[1.0, 0.0], [0.0, 1.0]]]), np.array([[[1.0, 0.0], [0.0, 1.0]]]) ]) test_gamma_0 = np.stack([np.r_[0.0, 1.0], np.r_[1.0, 0.0]]) test_dist = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=(2, 10)) test_sample = test_dist.random() assert np.array_equal(test_sample, np.stack([np.ones(10), np.zeros(10)], 0).astype(int)) assert test_sample.shape == (2, 10) # Now, the same set-up, but--this time--generate three state sequence # samples test_sample = test_dist.random(size=3) assert np.array_equal( test_sample, np.tile( np.stack([np.ones(10), np.zeros(10)], 0).astype(int), (3, 1, 1)), ) assert test_sample.shape == (3, 2, 10) # "Time"-varying transition matrices with a single vector of initial # probabilities test_Gamma = np.stack( [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), ], axis=0, ) test_gamma_0 = np.r_[1, 0] test_dist = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=3) test_sample = test_dist.random() assert np.array_equal(test_sample, np.r_[1, 0, 0]) # Now, the same set-up, but--this time--generate three state sequence # samples test_sample = test_dist.random(size=3) assert np.array_equal(test_sample, np.tile(np.r_[1, 0, 0].astype(int), (3, 1))) # "Time"-varying transition matrices with two initial # probabilities vectors test_Gamma = np.stack( [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), ], axis=0, ) test_gamma_0 = np.array([[1, 0], [0, 1]]) test_dist = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=(2, 3)) test_sample = test_dist.random() assert np.array_equal(test_sample, np.array([[1, 0, 0], [0, 1, 1]])) # Now, the same set-up, but--this time--generate three state sequence # samples test_sample = test_dist.random(size=3) assert np.array_equal( test_sample, np.tile(np.array([[1, 0, 0], [0, 1, 1]]).astype(int), (3, 1, 1))) # Two "Time"-varying transition matrices with two initial # probabilities vectors test_Gamma = np.stack( [ [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), ], [ np.array([[1.0, 0.0], [0.0, 1.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), ], ], axis=0, ) test_gamma_0 = np.array([[1, 0], [0, 1]]) test_dist = DiscreteMarkovChain.dist(test_Gamma, test_gamma_0, shape=(2, 3)) test_sample = test_dist.random() assert np.array_equal(test_sample, np.array([[1, 0, 0], [1, 1, 0]])) # Now, the same set-up, but--this time--generate three state sequence # samples test_sample = test_dist.random(size=3) assert np.array_equal( test_sample, np.tile(np.array([[1, 0, 0], [1, 1, 0]]).astype(int), (3, 1, 1)))
def test_DiscreteMarkovChain_logp(): theano.config.compute_test_value = "warn" # A single transition matrix and initial probabilities vector for each # element in the state sequence test_Gammas = np.array([[[0.0, 1.0], [1.0, 0.0]]]) test_gamma_0 = np.r_[1.0, 0.0] test_obs = np.r_[1, 0, 1, 0] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) assert test_logp_tt.eval() == 0 # "Time"-varying transition matrices with a single vector of initial # probabilities test_Gammas = np.stack( [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), ], axis=0, ) test_gamma_0 = np.r_[1.0, 0.0] test_obs = np.r_[1, 0, 1, 0] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) assert test_logp_tt.eval() == 0 # Static transition matrix and two state sequences test_Gammas = np.array([[[0.0, 1.0], [1.0, 0.0]]]) test_obs = np.array([[1, 0, 1, 0], [0, 1, 0, 1]]) test_gamma_0 = np.r_[0.5, 0.5] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) test_logp = test_logp_tt.eval() assert test_logp[0] == test_logp[1] # Time-varying transition matrices and two state sequences test_Gammas = np.stack( [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), ], axis=0, ) test_obs = np.array([[1, 0, 1, 0], [0, 1, 0, 1]]) test_gamma_0 = np.r_[0.5, 0.5] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) test_logp = test_logp_tt.eval() assert test_logp[0] == test_logp[1] # Two sets of time-varying transition matrices and two state sequences test_Gammas = np.stack( [ [ np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), np.array([[0.0, 1.0], [1.0, 0.0]]), ], [ np.array([[1.0, 0.0], [0.0, 1.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), np.array([[1.0, 0.0], [0.0, 1.0]]), ], ], axis=0, ) test_obs = np.array([[1, 0, 1, 0], [0, 0, 0, 0]]) test_gamma_0 = np.r_[0.5, 0.5] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) test_logp = test_logp_tt.eval() assert test_logp[0] == test_logp[1] # Two sets of time-varying transition matrices--via `gamma_0` # broadcasting--and two state sequences test_gamma_0 = np.array([[0.5, 0.5], [0.5, 0.5]]) test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) test_logp = test_logp_tt.eval() assert test_logp[0] == test_logp[1] # "Time"-varying transition matrices with a single vector of initial # probabilities, but--this time--with better test values test_Gammas = np.stack( [ np.array([[0.1, 0.9], [0.5, 0.5]]), np.array([[0.2, 0.8], [0.6, 0.4]]), np.array([[0.3, 0.7], [0.7, 0.3]]), np.array([[0.4, 0.6], [0.8, 0.2]]), ], axis=0, ) test_gamma_0 = np.r_[0.3, 0.7] test_obs = np.r_[1, 0, 1, 0] test_dist = DiscreteMarkovChain.dist(test_Gammas, test_gamma_0, shape=test_obs.shape[-1]) test_logp_tt = test_dist.logp(test_obs) logp_res = test_logp_tt.eval() logp_exp = np.concatenate( [ test_gamma_0.dot(test_Gammas[0])[None, ...], test_Gammas[(np.ogrid[1:4], test_obs[:-1])], ], axis=-2, ) logp_exp = logp_exp[(np.ogrid[:4], test_obs)] logp_exp = np.log(logp_exp).sum() assert np.allclose(logp_res, logp_exp)