def plot(self): """ Plot the joint Gaussian Mixture distribution. """ gaussian_components = [nlg.joint_distribution for nlg in self.nlgs] gaussian_mixture = GaussianMixture(gaussian_components) gaussian_mixture.plot()
def multiply(self, factor): """ Multiply this factor with another factor. :param factor: the factor to multiply with :return: the resulting factor :rtype: NonLinearGaussianMixture """ if isinstance(factor, GaussianMixture): gm_factor = factor elif isinstance(factor, Gaussian): gm_factor = GaussianMixture([Gaussian]) else: raise NotImplementedError() # TODO: Generalise the Gaussian.split_gaussian function to more than one dimensional cases and remove the # limitation here if self.split_singles_before_absorb and len(gm_factor.var_names) == 1: if len(gm_factor.components) == 1: gm_factor = gm_factor.components[0]._split_gaussian() new_nlgs = [] for gauss in gm_factor.components: for nlg in self.nlgs: new_nlgs.append(nlg.multiply(gauss)) return NonLinearGaussianMixture(new_nlgs)
def test_moment_match_to_single_gaussian(self): """ Test that the moment matching function returns a single Gaussian with the correct parameters. """ # TODO: add better test, with different means, here. gaussian_ab_5 = Gaussian( cov=[[2, 1], [1, 2]], mean=[0, 0], log_weight=np.log(0.5), var_names=["a", "b"] ) gaussian_ab_6 = Gaussian( cov=[[6, 3], [3, 6]], mean=[0, 0], log_weight=np.log(0.5), var_names=["a", "b"] ) gaussian_mixture = GaussianMixture([gaussian_ab_5, gaussian_ab_6]) actual_gaussian = gaussian_mixture.moment_match_to_single_gaussian() expected_gaussian = Gaussian( cov=[[4, 2], [2, 4]], mean=[0, 0], log_weight=np.log(1.0), var_names=["a", "b"] ) self.assertTrue(actual_gaussian.equals(expected_gaussian))
def test_equals_false_ncomps(self): """ Test that the equals function returns false for a GaussianMixture with a different number of components. """ gm3 = get_random_gaussian_mixture(num_components=3) gm4_components = gm3.copy().components + [gm3.components[0].copy()] gm4 = GaussianMixture(gm4_components) self.assertFalse(gm3.equals(gm4))
def test_marginalise(self): """ Test that the marginalize function results in the correct marginal components. """ expected_marginal_components = [ self.gaussian_ab_1.marginalize(vrs="a", keep=False), self.gaussian_ab_2.marginalize(vrs="a", keep=False), ] expected_gm = GaussianMixture(expected_marginal_components) actual_gm = self.gaussian_mixture_ab_12.marginalize(vrs="a", keep=False) self.assertTrue(actual_gm.equals(expected_gm))
def test_multiply_guassian(self): """ Test that the multiply function results in the correct components. """ expected_product_components = [ self.gaussian_ab_1.multiply(self.gaussian_ab_3), self.gaussian_ab_2.multiply(self.gaussian_ab_3), ] expected_gm = GaussianMixture(expected_product_components) actual_gm = self.gaussian_mixture_ab_12.multiply(self.gaussian_ab_3) self.assertTrue(actual_gm.equals(expected_gm))
def get_random_gaussian_mixture(cov_coeff=1.0, mean_coeff=1.0, num_components=3, seed=0): """ A test helper function that generates random Gaussian factors. :param n: the number of components. :param cov_coeff: The scale coefficient for the uniform distribution that the variance parameter is drawn from. :param mean_coeff: The scale coefficient for the uniform distribution that the mean parameter is drawn from. :return: a random Gaussian factor """ assert seed >= 0 random_gaussians = [] for i in range(num_components): comp_seed = (seed + 1) * i random_gaussians.append(get_random_gaussian(cov_coeff, mean_coeff, seed=comp_seed)) return GaussianMixture(random_gaussians)
def setUp(self): """ Run before every test. """ self.gaussian_ab_1 = Gaussian(cov=np.eye(2), mean=[1, 1], log_weight=1.0, var_names=["a", "b"]) self.gaussian_ab_2 = Gaussian(cov=np.eye(2), mean=[2, 2], log_weight=2.0, var_names=["a", "b"]) self.gaussian_ab_3 = Gaussian(cov=np.eye(2), mean=[3, 3], log_weight=3.0, var_names=["a", "b"]) self.gaussian_ab_4 = Gaussian(cov=np.eye(2), mean=[3, 3], log_weight=3.0, var_names=["a", "b"]) self.gaussian_cd_1 = Gaussian(cov=np.eye(2), mean=[1, 1], log_weight=1.0, var_names=["c", "d"]) self.gaussian_mixture_ab_34 = GaussianMixture(factors=[self.gaussian_ab_3, self.gaussian_ab_4]) self.gaussian_mixture_ab_12 = GaussianMixture(factors=[self.gaussian_ab_1, self.gaussian_ab_2]) self.gaussian_mixture_ab_123 = GaussianMixture( factors=[self.gaussian_ab_1, self.gaussian_ab_2, self.gaussian_ab_3] ) self.gaussian_mixture_ab_1_copy = GaussianMixture(factors=[self.gaussian_ab_1, self.gaussian_ab_2])
def joint_distribution(self): gaussian_joints = [] for nlg in self.nlgs: gaussian_joints.append(nlg.joint_distribution) return GaussianMixture(gaussian_joints)
def test_invalid_construction(self): """ Test that constructor fails with inconsistent scope Gaussian. """ with self.assertRaises(ValueError): GaussianMixture([self.gaussian_ab_1, self.gaussian_cd_1])
class TestGaussianMixture(unittest.TestCase): """ Tests for the GaussianMixture class """ def setUp(self): """ Run before every test. """ self.gaussian_ab_1 = Gaussian(cov=np.eye(2), mean=[1, 1], log_weight=1.0, var_names=["a", "b"]) self.gaussian_ab_2 = Gaussian(cov=np.eye(2), mean=[2, 2], log_weight=2.0, var_names=["a", "b"]) self.gaussian_ab_3 = Gaussian(cov=np.eye(2), mean=[3, 3], log_weight=3.0, var_names=["a", "b"]) self.gaussian_ab_4 = Gaussian(cov=np.eye(2), mean=[3, 3], log_weight=3.0, var_names=["a", "b"]) self.gaussian_cd_1 = Gaussian(cov=np.eye(2), mean=[1, 1], log_weight=1.0, var_names=["c", "d"]) self.gaussian_mixture_ab_34 = GaussianMixture(factors=[self.gaussian_ab_3, self.gaussian_ab_4]) self.gaussian_mixture_ab_12 = GaussianMixture(factors=[self.gaussian_ab_1, self.gaussian_ab_2]) self.gaussian_mixture_ab_123 = GaussianMixture( factors=[self.gaussian_ab_1, self.gaussian_ab_2, self.gaussian_ab_3] ) self.gaussian_mixture_ab_1_copy = GaussianMixture(factors=[self.gaussian_ab_1, self.gaussian_ab_2]) def test_invalid_construction(self): """ Test that constructor fails with inconsistent scope Gaussian. """ with self.assertRaises(ValueError): GaussianMixture([self.gaussian_ab_1, self.gaussian_cd_1]) def test_equals_not_gm_fails(self): """ Test that the equals function returns false when the factor comparing with is not a GaussianMixture. """ not_a_gm_factor = mockito.mock() gmix = get_random_gaussian_mixture() with self.assertRaises(TypeError): gmix.equals(not_a_gm_factor) def test_equals_true(self): """ Test that the equals function returns true for identical Gaussian mixtures. """ self.assertTrue(self.gaussian_mixture_ab_12.equals(self.gaussian_mixture_ab_1_copy)) def test_equals_false(self): """ Test that the equals function returns false for different Gaussian mixtures. """ self.assertFalse(self.gaussian_mixture_ab_12.equals(self.gaussian_mixture_ab_34)) def test_equals_false_ncomps(self): """ Test that the equals function returns false for a GaussianMixture with a different number of components. """ gm3 = get_random_gaussian_mixture(num_components=3) gm4_components = gm3.copy().components + [gm3.components[0].copy()] gm4 = GaussianMixture(gm4_components) self.assertFalse(gm3.equals(gm4)) def test_multiply_gm(self): """ Test that the multiply function results in the correct components. """ expected_product_components = [ self.gaussian_ab_1.multiply(self.gaussian_ab_3), self.gaussian_ab_1.multiply(self.gaussian_ab_4), self.gaussian_ab_2.multiply(self.gaussian_ab_3), self.gaussian_ab_2.multiply(self.gaussian_ab_4), ] expected_gm = GaussianMixture(expected_product_components) actual_gm = self.gaussian_mixture_ab_12.multiply(self.gaussian_mixture_ab_34) self.assertTrue(actual_gm.equals(expected_gm)) def test_multiply_guassian(self): """ Test that the multiply function results in the correct components. """ expected_product_components = [ self.gaussian_ab_1.multiply(self.gaussian_ab_3), self.gaussian_ab_2.multiply(self.gaussian_ab_3), ] expected_gm = GaussianMixture(expected_product_components) actual_gm = self.gaussian_mixture_ab_12.multiply(self.gaussian_ab_3) self.assertTrue(actual_gm.equals(expected_gm)) def test_multiply_invalid_type_fails(self): """ Test that the multiply function fails with invalid type. """ not_a_gm = mockito.mock() gma = get_random_gaussian_mixture() with self.assertRaises(TypeError): gma.multiply(not_a_gm) def test_marginalise(self): """ Test that the marginalize function results in the correct marginal components. """ expected_marginal_components = [ self.gaussian_ab_1.marginalize(vrs="a", keep=False), self.gaussian_ab_2.marginalize(vrs="a", keep=False), ] expected_gm = GaussianMixture(expected_marginal_components) actual_gm = self.gaussian_mixture_ab_12.marginalize(vrs="a", keep=False) self.assertTrue(actual_gm.equals(expected_gm)) def test_normalize(self): """ Test that the normalize function results in a a mixture with a weight of 1.0. """ normed_gm = self.gaussian_mixture_ab_123.normalize() log_weight = normed_gm.get_log_weight() actual_weight = np.exp(log_weight) self.assertAlmostEqual(actual_weight, 1.0) def test_moment_match_to_single_gaussian(self): """ Test that the moment matching function returns a single Gaussian with the correct parameters. """ # TODO: add better test, with different means, here. gaussian_ab_5 = Gaussian( cov=[[2, 1], [1, 2]], mean=[0, 0], log_weight=np.log(0.5), var_names=["a", "b"] ) gaussian_ab_6 = Gaussian( cov=[[6, 3], [3, 6]], mean=[0, 0], log_weight=np.log(0.5), var_names=["a", "b"] ) gaussian_mixture = GaussianMixture([gaussian_ab_5, gaussian_ab_6]) actual_gaussian = gaussian_mixture.moment_match_to_single_gaussian() expected_gaussian = Gaussian( cov=[[4, 2], [2, 4]], mean=[0, 0], log_weight=np.log(1.0), var_names=["a", "b"] ) self.assertTrue(actual_gaussian.equals(expected_gaussian)) def test_cancel_method_1(self): """ Test that the _gm_division_m2 function returns """ # TODO: improve this test. gaussian_mixture_1 = get_random_gaussian_mixture(cov_coeff=10, seed=1) gaussian_mixture_2 = get_random_gaussian_mixture(cov_coeff=10, seed=2) gaussian_mixture_12 = gaussian_mixture_1.multiply(gaussian_mixture_2) gaussian_mixture_12.cancel_method = 1 gaussian_mixture_quotient_approximation = gaussian_mixture_12.divide(gaussian_mixture_2) self.assertEqual(gaussian_mixture_quotient_approximation.num_components, 1) def test_cancel_method_2(self): """ Test that the _gm_division_m2 function returns. """ # TODO: improve this test. gaussian_mixture_1 = get_random_gaussian_mixture(cov_coeff=10, seed=1) gaussian_mixture_2 = get_random_gaussian_mixture(cov_coeff=10, seed=2) gaussian_mixture_12 = gaussian_mixture_1.multiply(gaussian_mixture_2) gaussian_mixture_12.cancel_method = 2 gaussian_mixture_quotient_approximation = gaussian_mixture_12.divide(gaussian_mixture_2) self.assertEqual(gaussian_mixture_quotient_approximation.num_components, 9)