def test_fit_single_random_long(): pi = np.array([0.3, 0.4, 0.3]) a = np.array([ [0.1, 0.1, 0.8], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3], [0.0, 0.0, 0.0, 0.5, 0.5] ]) model = dhmm.DiscreteHiddenMM(chain, b) sequence = np.random.choice(model.num_outputs, size=10000) model2 = model.fit_single(sequence) old_likelihood = model.likelihood(sequence) new_likelihood = model2.likelihood(sequence) assert new_likelihood >= old_likelihood
def test_log_likelihood_constant(): pi = np.array([1.0, 0.0, 0.0]) a = np.array([ [1.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [1.0, 0.0, 0.0, 0.0, 0.0], [0.1, 0.1, 0.2, 0.3, 0.3], [0.0, 0.0, 0.0, 0.5, 0.5] ]) model = dhmm.DiscreteHiddenMM(chain, b) sequence = np.random.choice(model.num_outputs, size=10) for i in range(100): likelihood = model.likelihood(sequence) log_likelihood = model.log_likelihood(sequence) assert np.allclose(np.log(likelihood), log_likelihood)
def test_fit_single(): pi = np.array([0.3, 0.4, 0.3]) a = np.array([ [0.1, 0.1, 0.8], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3], [0.0, 0.0, 0.0, 0.5, 0.5] ]) model = dhmm.DiscreteHiddenMM(chain, b) sequence = np.array([0, 1, 2, 3, 4]) model2 = model.fit_single(sequence) old_likelihood = model.likelihood(sequence) new_likelihood = model2.likelihood(sequence) assert new_likelihood >= old_likelihood
def test_likelihood_summation(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3] ]) model = dhmm.DiscreteHiddenMM(chain, b) summation = 0.0 for i in range(5): for j in range(5): for k in range(5): for z in range(5): observations = [i, j, k, z] likelihood = model.likelihood(np.array(observations, dtype=int)) assert likelihood >= 0.0 summation += likelihood assert np.abs(summation - 1.0) < cnst.EPSILON
def test_creation_dim_fails(): """ Dimension mismatch throws exception """ pi = np.array([0.1, 0.9, 0.5]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) mc.MarkovChain(pi, a)
def test_creation_negative_distribution(): """ Dimension mismatch throws exception """ pi = np.array([1.1, -0.1]) a = np.array([ [0.1, 0.9], [0.5, 0.4] ]) mc.MarkovChain(pi, a)
def test_creation_passes(): """ Simplistic test case to make sure setup works """ pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) mc.MarkovChain(pi, a)
def test_creation_distribution_sum_2(): """ Dimension mismatch throws exception """ pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.4] ]) mc.MarkovChain(pi, a)
def test_simple_generation(): """ Simple generation """ pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) model = mc.MarkovChain(pi, a) result = model.generate(n=100) assert result.shape[0] == 100 assert result.dtype == int
def test_constant_generation(): """ Simple generation """ pi = np.array([1.0, 0.0, 0.0]) a = np.array([ [1.0, 0.0, 0.0], [0.3, 0.4, 0.3], [0.1, 0.8, 0.1] ]) model = mc.MarkovChain(pi, a) result = model.generate(n=100) assert np.all(result < constants.EPSILON)
def test_distribution_negative(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.6, -0.2], [0.1, 0.1, 0.2, 0.3, 0.3], ]) dhmm.DiscreteHiddenMM(chain, b)
def test_successful_creation(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3] ]) dhmm.DiscreteHiddenMM(chain, b)
def test_distribution_does_not_sum_up(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.5] ]) dhmm.DiscreteHiddenMM(chain, b)
def test_dimension_mismatch(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3], [0.1, 0.1, 0.2, 0.3, 0.3] ]) dhmm.DiscreteHiddenMM(chain, b)
def test_solve_for_state_constant_chain(): pi = np.array([0.0, 0.0, 1.0]) a = np.array([ [1.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3], [0.0, 0.0, 0.0, 0.5, 0.5] ]) model = dhmm.DiscreteHiddenMM(chain, b) model.solve_for_states(np.array([0, 1, 2, 3, 4]))
def test_solve_for_state_list(): pi = np.array([1.0, 0.0, 0.0]) a = np.array([ [1.0, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3], [0.0, 0.0, 0.0, 0.5, 0.5] ]) model = dhmm.DiscreteHiddenMM(chain, b) assert np.allclose(model.solve_for_states(np.array([0, 1, 2, 3, 4])), 0)
def test_generation_1(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3] ]) model = dhmm.DiscreteHiddenMM(chain, b) result = model.generate(100) assert result.shape[0] == 100 assert result.shape[1] == 2
def test_likelihood_basic(): pi = np.array([0.1, 0.9]) a = np.array([ [0.1, 0.9], [0.5, 0.5] ]) chain = mc.MarkovChain(pi, a) b = np.array([ [0.2, 0.2, 0.2, 0.2, 0.2], [0.1, 0.1, 0.2, 0.3, 0.3] ]) model = dhmm.DiscreteHiddenMM(chain, b) assert np.abs(model.likelihood(np.array([0], dtype=int)) - 0.11) < cnst.EPSILON assert np.abs(model.likelihood(np.array([1], dtype=int)) - 0.11) < cnst.EPSILON assert np.abs(model.likelihood(np.array([2], dtype=int)) - 0.20) < cnst.EPSILON assert np.abs(model.likelihood(np.array([3], dtype=int)) - 0.29) < cnst.EPSILON assert np.abs(model.likelihood(np.array([4], dtype=int)) - 0.29) < cnst.EPSILON
def fit_single(self, observations: np.ndarray, stable=True) -> 'DiscreteHiddenMM': """ Perform an expectation-maximization procedure on the hidden markov chain model """ dimension = observations.shape[0] if dimension > 0: # Helper variables alpha, alpha_multipliers = self._helper_alpha(observations, stable=stable) beta, beta_multipliers = self._helper_beta(observations, stable=stable) # Output will be stored in these variables new_initial_distribution = np.zeros(self.num_states, dtype=float) new_transition_numerator = np.zeros( (self.num_states, self.num_states), dtype=float) new_transition_denominator = np.zeros( (self.num_states, self.num_states), dtype=float) new_projection_numerator = np.zeros( (self.num_states, self.num_outputs), dtype=float) new_projection_denominator = np.zeros( (self.num_states, self.num_outputs), dtype=float) # The actual content of the algorithm is iterating the xi matrix through time for i in range(dimension): gamma = (alpha[i] * beta[i]) / (alpha[i] * beta[i]).sum() # This piece is only executed in the first step if i == 0: new_initial_distribution = gamma # We have to skip the last step as there are one less transitions than observations if i < dimension - 1: xi_numerator = (self.transition_matrix * np.outer( alpha[i], self.projection[:, observations[i + 1]] * beta[i + 1])) xi = xi_numerator / xi_numerator.sum() new_transition_numerator += xi new_transition_denominator += gamma.reshape( (self.num_states, 1)) new_projection_numerator[:, observations[i]] += gamma new_projection_denominator += gamma.reshape( (self.num_states, 1)) new_transition = new_transition_numerator / new_transition_denominator new_projection = new_projection_numerator / new_projection_denominator # A way to handle divisions 0/0 new_transition = np.where(np.isnan(new_transition), np.eye(self.num_states), new_transition) new_projection = np.where(np.isnan(new_projection), 1.0 / self.num_outputs, new_projection) return DiscreteHiddenMM( mc.MarkovChain(new_initial_distribution, new_transition), new_projection) else: return self