Ejemplo n.º 1
0
 def test_make_scalar_fails_invalid_type(self):
     """
     Test that the make_scalar fails if the input has more than one value.
     """
     not_supported_type = mockito.mock()
     with self.assertRaises(TypeError):
         _factor_utils.make_scalar(not_supported_type)
Ejemplo n.º 2
0
 def test_make_scalar_fails_array_len(self):
     """
     Test that the make_scalar fails if the input has more than one value.
     """
     input_list = np.array([0.0, 1.0])
     with self.assertRaises(ValueError):
         _factor_utils.make_scalar(input_list)
Ejemplo n.º 3
0
    def test_make_scalar(self):
        """
        Test that the make_scalar returns the correct scalar value for different inputs.
        """

        expected_scalar = 0.0
        input_matrix = np.array([[0.0]])
        actual_scalar = _factor_utils.make_scalar(input_matrix)
        self.assertTrue(np.array_equal(expected_scalar, actual_scalar))

        expected_scalar = 1
        input_matrix = np.array([[1]])
        actual_scalar = _factor_utils.make_scalar(input_matrix)
        self.assertTrue(np.array_equal(expected_scalar, actual_scalar))

        expected_scalar = 0.0
        input_list = [0.0]
        actual_scalar = _factor_utils.make_scalar(input_list)
        self.assertTrue(np.array_equal(expected_scalar, actual_scalar))
Ejemplo n.º 4
0
    def _update_canform(self):
        """
        Update the canonical form parameters of the Gaussian.
        """
        if self.canform:
            return
        assert self.covform
        self.prec = _factor_utils.inv_matrix(self.cov)
        self.h_vec = self.prec @ self.mean
        utku = self.mean.T @ self.prec @ self.mean

        det_2pi_cov = np.linalg.det(2.0 * np.pi * self.cov)
        updated_g_val = self.log_weight - 0.5 * utku - 0.5 * _factor_utils.log(det_2pi_cov)

        self.g_val = _factor_utils.make_scalar(updated_g_val)
        self.canform = True
Ejemplo n.º 5
0
 def _update_covform(self):
     """
     Update the covariance form parameters of the Gaussian.
     """
     if self._is_vacuous:
         raise Exception("cannot update covariance form for vacuous Gaussian.")
     if self.covform:
         return
     assert self.canform
     self.cov = _factor_utils.inv_matrix(self.prec)
     assert not np.isnan(np.sum(self.cov)), "Error: nan values in cov matrix after inversion."
     self.mean = self.cov @ self.h_vec
     utku = self.mean.T @ self.prec @ self.mean
     det_2_pi_cov = np.linalg.det(2.0 * np.pi * self.cov)
     log_weight_ = self.g_val + 0.5 * utku + 0.5 * np.log(det_2_pi_cov)
     self.log_weight = _factor_utils.make_scalar(log_weight_)
     self.covform = True
Ejemplo n.º 6
0
    def __init__(self, cov=None, mean=None, log_weight=None, prec=None, h_vec=None, g_val=None, var_names=None):
        """
        General constructor that can use either covariance form or canonical form parameters to construct a
        d-dimensional multivariate Gaussian object.

        :param cov: (covariance form) The covariance matrix (or variance scalar in 1-dimensional case).
        :type cov: dxd numpy.ndarray or float
        :param mean: (covariance form) The mean vector (or mean scalar in 1-dimensional case).
        :type mean: dx1 numpy.ndarray or float
        :param log_weight: (covariance form) The log of the weight (the Gaussian function integrates to the weight value)
        :type log_weight: float
        :param prec: (canonical form) The precision matrix (or precision scalar in 1-dimensional case).
        :type prec: dxd numpy.ndarray or float
        :param h_vec: (canonical form) The h vector  (or h scalar in 1-dimensional case).
        :type h_vec: dx1 numpy.ndarray or float
        :param g_val: (canonical form) The g parameter.
        :type g_val: float
        :param var_names: a list of variable names where the order of the names correspond to the order in the
                         mean and covariance (or precision and h vector)  parameters.
        :type var_names: str list

        Example:

        .. code-block:: python

            # Using covariance form parameters
            >>> Gaussian(cov=[[1, 0], [0, 1]], mean=[0, 0], log_weight=0.0, var_names=["a", "b"])
            # Using canonical form parameters
            >>> Gaussian(prec=[[1, 0], [0, 1]], h_vec=[0, 0], g_val=0.0, var_names=["a", "b"])

        """

        super().__init__(var_names=var_names)
        self._is_vacuous = False
        if all(v is None for v in [prec, h_vec, g_val]):
            if any(v is None for v in [cov, mean, log_weight]):
                raise ValueError("incomplete parameters")
            self.cov = _factor_utils.make_square_matrix(cov)
            self.mean = _factor_utils.make_column_vector(mean)
            assert len(self.cov.shape) == 2, "Error: Covariance matrix must be two dimensional."

            assert self.cov.shape[0] == self.dim, "Error: Covariance matrix dimension inconsistency."
            assert self.mean.shape[0] == self.dim, "Error: Mean vector dimension inconsistency."
            self.log_weight = _factor_utils.make_scalar(log_weight)
            self.prec, self.h_vec, self.g_val = None, None, None
            self.canform = False
            self.covform = True
        else:
            if any(v is None for v in [prec, h_vec, g_val]):
                raise ValueError("incomplete parameters")
            self.prec = _factor_utils.make_square_matrix(prec)
            self.h_vec = _factor_utils.make_column_vector(h_vec)
            if self.prec.shape[0] != self.dim:
                pass
            assert len(self.prec.shape) == 2, "Error: Precision matrix must be two dimensional."
            assert self.prec.shape[0] == self.dim, "Error: Precision matrix dimension inconsistency."
            h_error_msg = f"Error: h vector dimension inconsistency: {self.h_vec.shape[0]} (should be {self.dim})"
            assert self.h_vec.shape[0] == self.dim, h_error_msg
            self.g_val = _factor_utils.make_scalar(g_val)
            self.cov, self.mean, self.log_weight = None, None, None
            self.canform = True
            self.covform = False

            # Note: this is important to allow vacuous Gaussians (that arise, for exmaple, when Gaussians are divided by
            # identical distributions or with unconditioned nonlinear Gaussians) to be merginalised.
            if self.is_vacuous:
                self._is_vacuous = True