Пример #1
0
    def _cov_mat(self, x1, x2=None, noise=True):
        """
        Covariance matrix for preference data using the kernel function.
        :param x1:      datapoints for which to compute covariance matrix
        :param x2:      if None, covariance matrix will be square for the input x1
                        if not None, covariance will be between x1 (rows) and x2 (cols_
        :param noise:   whether to add noise to the diagonal of the covariance matrix
        :return:
        """
        if x2 is None:
            x2 = x1
        else:  # if x1 != x2 we don't add noise!
            noise = False

        x1 = utils_data.format_data(x1, self.num_objectives)
        x2 = utils_data.format_data(x2, self.num_objectives)

        cov_mat = self._kernel(np.repeat(x1, x2.shape[0], axis=0),
                               np.tile(x2, (x1.shape[0], 1)))
        cov_mat = cov_mat.reshape((x1.shape[0], x2.shape[0]))

        if noise:
            cov_mat += self.std_noise**2 * np.eye(cov_mat.shape[0])

        return cov_mat
Пример #2
0
 def _kernel(self, x1, x2):
     """
     Squared exponential kernel function
     :param x1:
     :param x2:
     :return:
     """
     x1 = utils_data.format_data(x1, self.num_objectives)
     x2 = utils_data.format_data(x2, self.num_objectives)
     k = 0.8**2 * np.exp(-(1. / (2. * (self.kernel_width**2))) *
                         np.linalg.norm(x1 - x2, axis=1)**2)
     return k
Пример #3
0
    def get_predictive_params(self, x_new, pointwise):
        """
        Returns the predictive parameters (mean, variance) of the Gaussian distribution
        at the given datapoints
        :param x_new:    the points for which we want the predictive params
        :param pointwise:       whether we want pointwise variance or the entire covariance matrix
        :return:
        """
        # bring input points into right shape
        x_new = utils_data.format_data(x_new, self.num_objectives)

        # if we don't have any data yet, use prior GP to make predictions
        if self.datapoints is None or self.utility_vals is None:
            pred_mean, pred_var = self._evaluate_prior(x_new)

        # otherwise compute predictive mean and covariance
        else:
            cov_xnew_x = self._cov_mat(x_new, self.datapoints, noise=False)
            cov_x_xnew = self._cov_mat(self.datapoints, x_new, noise=False)
            cov_xnew = self._cov_mat(x_new, noise=False)
            pred_mean = self.prior_mean(x_new) + np.dot(
                np.dot(cov_xnew_x, self.cov_mat_inv),
                (self.utility_vals - self.prior_mean(self.datapoints)))
            pred_var = cov_xnew - np.dot(
                np.dot(cov_xnew_x, self.pred_cov_factor), cov_x_xnew)

        if pointwise:
            pred_var = pred_var.diagonal()

        return pred_mean, pred_var
Пример #4
0
    def get_predictive_params(self, x_new, pointwise):

        # make sure data is in right shape
        x_new = utils_data.format_data(x_new, self.num_objectives)

        # if we don't have any data yet, use prior GP to make predictions
        if self.x_dx.shape[0] == 0 or self.utility_vals is None:
            pred_mean, pred_var = self._evaluate_prior(x_new)

        # otherwise compute predictive mean and covariance
        else:
            cov_in_data = self._cov_mat_incl_deriv(x1=x_new,
                                                   x2=self.datapoints,
                                                   dx2=self.datapoints_deriv)
            cov_data_in = self._cov_mat_incl_deriv(x1=self.datapoints,
                                                   dx1=self.datapoints_deriv,
                                                   x2=x_new)
            cov_lamb_inv = np.linalg.inv(self.cov_mat - self.lambda_mat_inv)
            pred_mean = self.prior_mean(x_new) + np.dot(
                np.dot(cov_in_data, self.cov_mat_inv),
                (self.utility_vals - self.prior_joint_mean(
                    self.datapoints, self.datapoints_deriv)))
            pred_var = self._kernel(x_new, x_new) - np.dot(
                np.dot(cov_in_data, cov_lamb_inv), cov_data_in)
        if pointwise:
            pred_var = pred_var.diagonal()

        return pred_mean, pred_var
Пример #5
0
 def prior_mean(self, x):
     """
     Prior mean function
     :param x:   num_datapoints * num_objectives
     :return:
     """
     x = utils_data.format_data(x, self.num_objectives)
     m = np.zeros(x.shape[0])
     if self.prior_mean_type == 'linear':
         m += np.sum(x, axis=1) / self.num_objectives
     else:
         TypeError('Prior mean type not understood.')
     return m
Пример #6
0
 def prior_mean_deriv(self, x):
     """
     Derivative of prior mean function
     :param x:
     :return:
     """
     x = utils_data.format_data(x, self.num_objectives)
     if self.prior_mean_type == 'zero':
         dm = np.zeros(x.shape[0])
     elif self.prior_mean_type == 'linear':
         dm = np.ones(x.shape[0]) / self.num_objectives
     else:
         TypeError('Prior mean type not understood.')
     return dm
Пример #7
0
    def sample(self, sample_points):
        """
        Get a sample from the current GP at the given points.
        :param sample_points:   the points at which we want to take the sample
        :return:                the values of the GP sample at the input points
        """
        # bring sample points in right shape
        sample_points = utils_data.format_data(sample_points,
                                               self.num_objectives)

        # get the mean and the variance of the predictive (multivariate gaussian) distribution at the sample points
        mean, var = self.get_predictive_params(sample_points, pointwise=False)

        # sample from the multivariate gaussian with the given parameters
        f_sample = self.random_state.multivariate_normal(mean, var, 1)[0]

        return f_sample
Пример #8
0
    def update(self, dataset, dx):
        """ pairwise dataset and virtual derivative points """
        self.datapoints = dataset.datapoints
        self.comparisons = dataset.comparisons

        # x-values at which we make virtual derivative observations
        self.datapoints_deriv = utils_data.format_data(dx, self.num_objectives)

        # x-values for real observations and derivative observations
        self.x_dx = np.concatenate((self.datapoints, self.datapoints_deriv))

        # update the covariance matrix
        self.cov_mat = self._cov_mat_incl_deriv(self.datapoints,
                                                self.datapoints_deriv)
        self.cov_mat_inv = np.linalg.inv(self.cov_mat)

        # update the map estimate of f
        self.utility_vals = self._compute_posterior()
Пример #9
0
    def _add_single_datapoint(self, new_datapoint):
        """
        Add single datapoint to the existing dataset if it doesn't exist yet and return index
        :param new_datapoint:       new datapoint to add
        :return x_new_idx:  the index of the new datapoint in the existing dataset
        """
        new_datapoint = utl_data.format_data(new_datapoint,
                                             self.num_objectives)

        # if the datapoint is not in our dataset yet, add it
        if not utl_data.array_in_matrix(new_datapoint, self.datapoints):
            self.datapoints = np.vstack((self.datapoints, new_datapoint))
            new_datapoint_index = self.datapoints.shape[0] - 1

        # if the datapoint is already in our dataset, find its index
        else:
            new_datapoint_index = self.get_index(new_datapoint)

        return new_datapoint_index
Пример #10
0
    def get_preference(self, x, add_noise):

        # bring data into right format first
        x = utils_data.format_data(x, self.num_objectives)

        # EVALUATE user preferences
        if self.num_objectives == 1:
            y = np.polyval(self.poly, x)
        else:
            y = self.utility_func(x)
        y = y.flatten()
        assert len(y) == x.shape[0]
        y = (y - self.min_y) / (self.max_y - self.min_y)

        if add_noise:
            # the noise is different every time the scalarisation function is called,
            # but we always draw from the same distribution
            noise = self.random_state.normal(0, self.std_noise, x.shape[0])
            y += noise

        return y
Пример #11
0
 def _kernel(self, x1, x2):
     x1 = utils_data.format_data(x1, self.num_objectives)
     x2 = utils_data.format_data(x2, self.num_objectives)
     k = 0.8**2 * np.exp(-(1. / (2. * (self.kernel_width**2))) *
                         np.linalg.norm(x1 - x2, axis=1)**2)
     return k