Example #1
0
    def compute_var(self, X, xTest):
        """
        compute variance given X and xTest
        
        Input Parameters
        ----------
        X: the observed points
        xTest: the testing points 
        
        Returns
        -------
        diag(var)
        """

        xTest = np.asarray(xTest)
        if self.kernel_name == 'SE':
            #Euc_dist=euclidean_distances(xTest,xTest)
            #KK_xTest_xTest=np.exp(-np.square(Euc_dist)/self.lengthscale)+np.eye(xTest.shape[0])*self.noise_delta
            ur = unique_rows(X)
            X = X[ur]
            if xTest.shape[0] < 300:
                Euc_dist_test_train = euclidean_distances(xTest, X)
                #Euc_dist_test_train=dist(xTest, X, matmul='gemm', method='ext', precision='float32')
                KK_xTest_xTrain = np.exp(-np.square(Euc_dist_test_train) /
                                         self.lengthscale)
            else:
                KK_xTest_xTrain = cdist(
                    xTest, X,
                    lambda a, b: self.kernel_dist(a, b, self.lengthscale))

            Euc_dist_train_train = euclidean_distances(X, X)
            self.KK_bucb_train_train = np.exp(
                -np.square(Euc_dist_train_train) /
                self.lengthscale) + np.eye(X.shape[0]) * self.noise_delta
        else:
            #KK=pdist(xTest,lambda a,b: self.kernel_dist(a,b,self.lengthscale))
            #KK=squareform(KK)
            #KK_xTest_xTest=KK+np.eye(xTest.shape[0])*(1+self.noise_delta)
            ur = unique_rows(X)
            X = X[ur]
            KK_xTest_xTrain = cdist(
                xTest, X,
                lambda a, b: self.kernel_dist(a, b, self.lengthscale))
            self.KK_bucb_train_train = cdist(
                X, X, lambda a, b: self.kernel_dist(a, b, self.lengthscale)
            ) + np.eye(X.shape[0]) * self.noise_delta
        try:
            temp = np.linalg.solve(self.KK_bucb_train_train, KK_xTest_xTrain.T)
        except:
            temp = np.linalg.lstsq(self.KK_bucb_train_train,
                                   KK_xTest_xTrain.T,
                                   rcond=-1)
            temp = temp[0]

        #var=KK_xTest_xTest-np.dot(temp.T,KK_xTest_xTrain.T)
        var = np.eye(xTest.shape[0]) - np.dot(temp.T, KK_xTest_xTrain.T)
        var = np.diag(var)
        var.flags['WRITEABLE'] = True
        var[var < 1e-100] = 0
        return var
    def init_with_data(self, init_X, init_Y):
        """      
        Input parameters
        ----------
        gp_params:            Gaussian Process structure      
        x,y:        # init data observations (in original scale)
        """

        # Turn it into np array and store.
        self.X_original = np.asarray(init_X)
        temp_init_point = np.divide((init_X - self.bounds[:, 0]),
                                    self.max_min_gap)

        self.X_original = np.asarray(init_X)
        self.X = np.asarray(temp_init_point)

        self.Y_original = np.asarray(init_Y)
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))

        self.NumPoints = np.append(self.NumPoints, len(init_Y))

        # Set acquisition function
        self.acq_func = AcquisitionFunction(self.acq)

        # Find unique rows of X to avoid GP from breaking
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])
    def posterior(self, Xnew):
        #xmin, xmax = -2, 10
        ur = unique_rows(self.X)

        self.gp.fit(self.X[ur], self.Y[ur])
        mu, sigma2 = self.gp.predict(Xnew, eval_MSE=True)
        return mu, np.sqrt(sigma2)
Example #4
0
    def predict(self, xTest, eval_MSE=True):
        """
        compute predictive mean and variance
        Input Parameters
        ----------
        xTest: the testing points 
        
        Returns
        -------
        mean, var
        """
        if len(xTest.shape) == 1:  # 1d
            xTest = np.array(xTest.reshape((-1, self.X.shape[1])))

        # prevent singular matrix
        ur = unique_rows(self.X)
        X = self.X[ur]
        Y = self.Y[ur]

        #KK=pdist(xTest,lambda a,b: self.ARD_dist_func(a,b,self.theta))

        if self.kernel_name == 'SE':
            Euc_dist = euclidean_distances(xTest, xTest)
            KK_xTest_xTest = np.exp(
                -np.square(Euc_dist) /
                self.lengthscale) + np.eye(xTest.shape[0]) * self.noise_delta

            Euc_dist_test_train = euclidean_distances(xTest, X)
            KK_xTest_xTrain = np.exp(-np.square(Euc_dist_test_train) /
                                     self.lengthscale)
        else:
            KK = pdist(xTest,
                       lambda a, b: self.kernel_dist(a, b, self.lengthscale))
            KK = squareform(KK)
            KK_xTest_xTest = KK + np.eye(
                xTest.shape[0]) + np.eye(xTest.shape[0]) * self.noise_delta
            KK_xTest_xTrain = cdist(
                xTest, X,
                lambda a, b: self.kernel_dist(a, b, self.lengthscale))

        temp = np.dot(KK_xTest_xTrain, self.KK_x_x_inv)
        mean = np.dot(temp, self.Y)
        var = KK_xTest_xTest - np.dot(temp, KK_xTest_xTrain.T)
        """
        if self.flagIncremental==1:
            temp=np.dot(KK_xTest_xTrain,self.KK_x_x_inv)
            mean=np.dot(temp,self.Y)
            var=KK_xTest_xTest-np.dot(temp,KK_xTest_xTrain.T)
        else:
            try:
                temp=np.linalg.solve(self.KK_x_x+self.noise_delta,KK_xTest_xTrain.T)
            except:
                temp=np.linalg.lstsq(self.KK_x_x+self.noise_delta,KK_xTest_xTrain.T, rcond=-1)
                temp=temp[0]
            mean=np.dot(temp.T,Y)
            var=KK_xTest_xTest-np.dot(temp.T,KK_xTest_xTrain.T)
        """

        return mean.ravel(), np.diag(var)
Example #5
0
    def predict_topk(self, xTest, k_neighbors=1):
        """
        compute predictive mean and variance using top k nearest neighbors
        Input Parameters
        ----------
        xTest: the testing points 
        
        Returns
        -------
        mean, var
        """
        def k_smallest(a, N):
            if len(a) < N:
                return xrange(len(a))

            #return np.argsort(a)[:N] (N = len(a))
            return np.argsort(a)[:N]

        def k_smallest_matrix(a, N):
            return np.argsort(a, axis=1)[:, :N]

        if len(xTest.shape) == 1:  # 1d
            xTest = xTest.reshape((-1, self.X.shape[1]))

        # prevent singular matrix
        ur = unique_rows(self.X)
        X = self.X[ur]
        Y = self.Y[ur]

        Euc_dist = euclidean_distances(xTest, xTest)
        #KK_xTest_xTest=np.exp(-self.theta*np.square(Euc_dist))+self.noise_delta
        KK_xTest_xTest = np.exp(-self.theta * np.square(Euc_dist))

        Euc_dist = euclidean_distances(xTest, X)

        dist = []
        neighbor_idx = []
        # find top K in X which are the nearest to xTest
        for idx, val in enumerate(xTest):
            # distance to the closest
            selected_idx = k_smallest(Euc_dist[idx, :], k_neighbors)
            neighbor_idx.append(selected_idx)

            temp = Euc_dist[idx, selected_idx]
            temp = np.prod(temp)
            dist.append(temp)
        Euc_dist_topk = np.asarray(dist)
        Euc_dist_topk = np.atleast_2d(Euc_dist_topk).T

        #KK_xTest_xTrain=np.exp(-self.theta*np.square(Euc_dist))
        KK_xTest_xTrain_topK = np.exp(-self.theta * np.square(Euc_dist_topk))

        #neighbor_idx=np.atleast_1d(neighbor_idx).ravel()
        mean = KK_xTest_xTrain_topK
        var = 1 - KK_xTest_xTrain_topK

        return mean.ravel(), var.ravel()
Example #6
0
    def predict_bucb(self, xTest, eval_MSE):
        """
        compute predictive mean and variance for BUCB        
        
        Input Parameters
        ----------
        xTest: the testing points 
        
        Returns
        -------
        mean, var
        """

        if len(xTest.shape) == 1:  # 1d
            xTest = xTest.reshape((-1, self.X.shape[1]))

        #Euc_dist=euclidean_distances(xTest,xTest)
        #KK_xTest_xTest=np.exp(-self.theta*np.square(Euc_dist))+self.noise_delta

        if self.kernel_name == 'SE':
            Euc_dist = euclidean_distances(xTest, xTest)
            KK_xTest_xTest = np.exp(
                -np.square(Euc_dist) /
                self.lengthscale) + np.eye(xTest.shape[0]) * self.noise_delta

            ur = unique_rows(self.X)
            X = self.X[ur]

            Euc_dist_test_train = euclidean_distances(xTest, X)
            KK_xTest_xTrain = np.exp(-np.square(Euc_dist_test_train) /
                                     self.lengthscale)

            Euc_dist_train_train = euclidean_distances(X, X)
            self.KK_bucb_train_train = np.exp(
                -np.square(Euc_dist_train_train) /
                self.lengthscale) + np.eye(X.shape[0]) * self.noise_delta

        #Euc_dist=euclidean_distances(xTest,self.X)
        #KK_xTest_xTrain=np.exp(-self.theta*np.square(Euc_dist))

        # computing the mean using the old data
        try:
            temp = np.linalg.solve(
                self.KK_x_x + np.eye(self.X.shape[0]) * self.noise_delta,
                KK_xTest_xTrain.T)
        except:
            temp = np.linalg.lstsq(self.KK_x_x +
                                   np.eye(self.X.shape[0]) * self.noise_delta,
                                   KK_xTest_xTrain.T,
                                   rcond=-1)
            temp = temp[0]
        mean = np.dot(temp.T, self.Y)

        var = self.compute_var(self.X_bucb, xTest)

        return mean.ravel(), var
    def fit(self, x, y):
        # fit the model, given the observation x and y
        self.X = x
        self.Y = y

        ur = unique_rows(self.X)
        x = x[ur]
        y = y[ur]

        Euc_dist = euclidean_distances(x, x)

        self.KK_x_x = []
        for idx in range(self.nGP):
            temp = np.exp(
                -self.theta[idx] * np.square(Euc_dist)) + self.noise_delta
            self.KK_x_x.append(temp)
    def predict(self, xTest, eval_MSE):
        """
        compute predictive mean and variance
        Input Parameters
        ----------
        xTest: the testing points 
        
        Returns
        -------
        mean, var
        """
        if len(xTest.shape) == 1:  # 1d
            xTest = xTest.reshape((-1, self.X.shape[1]))

        # prevent singular matrix
        ur = unique_rows(self.X)
        X = self.X[ur]
        Y = self.Y[ur]

        Euc_dist = euclidean_distances(xTest, xTest)
        #KK_xTest_xTest=np.exp(-self.theta*np.square(Euc_dist))+self.noise_delta
        KK_xTest_xTest = np.exp(-self.theta * np.square(Euc_dist))

        Euc_dist = euclidean_distances(xTest, X)
        KK_xTest_xTrain = np.exp(-self.theta * np.square(Euc_dist))

        #mean=np.dot(temp.T,self.Y)

        if self.flagIncremental == 1:
            temp = np.dot(KK_xTest_xTrain, self.KK_x_x_inv)
            mean = np.dot(temp, self.Y)
            var = KK_xTest_xTest - np.dot(temp, KK_xTest_xTrain.T)
        else:
            try:
                temp = np.linalg.solve(self.KK_x_x + self.noise_delta,
                                       KK_xTest_xTrain.T)
            except:
                temp = np.linalg.lstsq(self.KK_x_x + self.noise_delta,
                                       KK_xTest_xTrain.T,
                                       rcond=-1)
                temp = temp[0]
            mean = np.dot(temp.T, Y)
            var = KK_xTest_xTest + self.noise_delta - np.dot(
                temp.T, KK_xTest_xTrain.T)

        return mean.ravel(), np.diag(var)
    def fit(self, X, Y):
        """
        Fit Gaussian Process model

        Input Parameters
        ----------
        x: the observed points 
        y: the outcome y=f(x)
        
        """

        ur = unique_rows(X)
        X = X[ur]
        Y = Y[ur]

        self.X = X
        self.Y = Y
        Euc_dist = euclidean_distances(X, X)
        self.KK_x_x = np.exp(
            -self.theta * np.square(Euc_dist)) + self.noise_delta
        self.KK_x_x_inv = np.linalg.pinv(self.KK_x_x)
    def fit(self, x, y):
        """
        Fit Gaussian Process model

        Input Parameters
        ----------
        x: the observed points 
        y: the outcome y=f(x)
        
        """
        self.X = x
        self.Y = y

        ur = unique_rows(self.X)
        x = x[ur]
        y = y[ur]

        Euc_dist = euclidean_distances(x, x)
        self.KK_x_x = np.exp(
            -self.theta * np.square(Euc_dist)) + self.noise_delta
        self.KK_x_x_inv = np.linalg.pinv(self.KK_x_x)
Example #11
0
        def compute_log_marginal(X, lengthscale, noise_delta):
            """
            def ARD_dist_func(A,B,length_scale):
                mysum=0
                for idx,val in enumerate(length_scale):
                    mysum=mysum+((A[idx]-B[idx])**2)/val
                    #print mysum
                dist=np.exp(-mysum)
                return dist
            """
            # compute K
            ur = unique_rows(self.X)
            dim = X.shape[1]
            myX = self.X[ur]
            myY = self.Y[ur]
            D = np.hstack((myX, myY.reshape(-1, 1)))
            LLO = 0
            for i in range(0, D.shape[0]):
                D_train = np.delete(D, i, 0)
                D_test = D[i, :]
                Xtrain = D_train[:, 0:dim]
                Ytrain = D_train[:, dim]
                Xtest = D_test[0:dim]
                Ytest = D_test[dim]
                gp_params = {'theta': lengthscale, 'noise_delta': noise_delta}
                gp = PradaGaussianProcess(gp_params)
                gp.fit(Xtrain, Ytrain)
                mu, sigma2 = gp.predict(Xtest, eval_MSE=True)
                logmarginal = -(1 / 2) * np.log(sigma2) - np.square(
                    Ytest - mu) / (2 * sigma2)
                LLO += logmarginal
#                if (np.isnan(np.asscalar(logmarginal))==True):
#                    print "theta={:s} first term ={:.4f} second  term ={:.4f}".format(lengthscale,np.asscalar(first_term),np.asscalar(second_term))
#                    #print temp_det
#print("likelihood for {}={}".format(lengthscale,LLO))
            return np.asscalar(LLO)
Example #12
0
    def fit(self, X, Y):
        """
        Fit Gaussian Process model

        Input Parameters
        ----------
        x: the observed points 
        y: the outcome y=f(x)
        
        """
        ur = unique_rows(X)
        X = X[ur]
        Y = Y[ur]

        self.X = X
        self.Y = Y

        #KK=pdist(self.X,lambda a,b: self.ARD_dist_func(a,b,self.theta))

        if self.kernel_name == 'SE':
            Euc_dist = euclidean_distances(X, X)
            self.KK_x_x = np.exp(
                -np.square(Euc_dist) /
                self.lengthscale) + np.eye(len(X)) * self.noise_delta
        else:
            KK = pdist(self.X,
                       lambda a, b: self.kernel_dist(a, b, self.lengthscale))
            KK = squareform(KK)
            self.KK_x_x = KK + np.eye(self.X.shape[0]) * (1 + self.noise_delta)

        #Euc_dist=euclidean_distances(X,X)
        #self.KK_x_x=np.exp(-self.theta*np.square(Euc_dist))+self.noise_delta

        if np.isnan(self.KK_x_x).any():  #NaN
            print "bug"
        self.KK_x_x_inv = np.linalg.pinv(self.KK_x_x)
    def maximize_expanding_volume_L(self, gp_params):
        """
        Expanding volume following L ~ MaxIter

        Input parameters
        ----------

        gp_params: parameter for Gaussian Process

        Returns
        -------
        x: recommented point for evaluation
        """

        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=1) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.time_opt = np.hstack((self.time_opt, 0))
            return

        # init a new Gaussian Process
        self.gp = PradaGaussianProcess(gp_params)

        # scale the data before updating the GP
        # convert it to scaleX
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # Set acquisition function
        start_opt = time.time()

        y_max = self.Y.max()

        #self.L=self.estimate_L(self.scalebounds)
        # select the acquisition function

        self.acq_func = AcquisitionFunction(self.acq)

        # consider the expansion step

        # backup the previous bounds
        self.bounds_bk = self.bounds.copy()
        self.scalebounds_bk = self.scalebounds.copy()

        # the region considered is computed as follows: NewVol~OldVol*T/t
        # alternatively, we compute the radius NewL~Oldl*pow(T/t,1/d)
        new_radius = self.l_radius * np.power(
            self.MaxIter / len(self.Y_original), 1.0 / self.dim)
        # extra proportion
        extra_proportion = new_radius * 1.0 / self.l_radius

        #extra_radius=(new_radius-self.l_radius)/2

        if extra_proportion < 1:
            extra_proportion = 1

        max_bounds = self.bounds.copy()

        # expand half to the lower bound and half to the upper bound
        max_bounds[:, 0] = max_bounds[:, 0] - self.max_min_gap * (
            extra_proportion - 1) * 0.5
        max_bounds[:, 1] = max_bounds[:, 1] + self.max_min_gap * (
            extra_proportion - 1) * 0.5

        # make sure it is within the limit
        if not (self.b_limit_lower is None):
            temp_max_bounds_lower = [
                np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx])
                for idx in xrange(self.dim)
            ]
            max_bounds[:, 0] = temp_max_bounds_lower

        if not (self.b_limit_upper is None):
            temp_max_bounds_upper = [
                np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx])
                for idx in xrange(self.dim)
            ]
            max_bounds[:, 1] = temp_max_bounds_upper

        temp = [(max_bounds[d, :] - self.bounds_bk[d, 0]) * 1.0 /
                self.max_min_gap[d] for d in xrange(self.dim)]
        self.scalebounds = np.asarray(temp)

        # perform standard BO on the new bound (scaled)
        x_max_scale = acq_max(ac=self.acq_func.acq_kind,
                              gp=self.gp,
                              y_max=y_max,
                              bounds=self.scalebounds,
                              opt_toolbox=self.opt_toolbox)

        #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max)
        #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0])

        # record the optimization time
        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.time_opt = np.hstack((self.time_opt, elapse_opt))

        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max_scale).sum(axis=1) == 0):
            x_max_scale = np.random.uniform(self.scalebounds[:, 0],
                                            self.scalebounds[:, 1],
                                            size=self.scalebounds.shape[0])

        # check if the estimated data point is in the old bound or new for cropping
        IsCropping = 0
        if IsCropping == 1:
            flagOutside = 0
            for d in xrange(self.dim):
                if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[
                        d] < self.scalebounds_bk[d, 0]:  #outside the old bound
                    flagOutside = 1
                    self.scalebounds[d,
                                     0] = np.minimum(x_max_scale[d],
                                                     self.scalebounds_bk[d, 0])
                    self.scalebounds[d,
                                     1] = np.maximum(x_max_scale[d],
                                                     self.scalebounds_bk[d, 1])

                    # now the scalebounds is no longer 0-1

            if flagOutside == 0:  # not outside the old bound
                self.scalebounds = self.scalebounds_bk
                self.bounds = self.bounds_bk.copy()
            else:  # inside the old bound => recompute bound
                temp = [
                    self.scalebounds[d, :] * self.max_min_gap[d] +
                    self.bounds_bk[d, 0] for d in xrange(self.dim)
                ]
                if self.dim > 1:
                    self.bounds = np.reshape(temp, (self.dim, 2))
                else:
                    self.bounds = np.array(temp)
        else:
            temp = [
                self.scalebounds[d, :] * self.max_min_gap[d] +
                self.bounds_bk[d, 0] for d in xrange(self.dim)
            ]
            if self.dim > 1:
                self.bounds = np.reshape(temp, (self.dim, 2))
            else:
                self.bounds = np.array(temp)

        # compute X in original scale
        temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:,
                                                                              0]
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        # clone the self.X for updating GP
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)])
        self.scalebounds = scalebounds.T
        # evaluate Y using original X

        self.Y_original = np.append(self.Y_original,
                                    self.f(temp_X_new_original))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))

        # for plotting
        self.gp = PradaGaussianProcess(gp_params)
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # update volume and radius
        #self.vol=prod(self.max_min_gap)
        #self.l_radius=np.power(self.vol,1/self.dim)
        self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) /
                               self.dim)
    def maximize_unbounded_regularizer(self, gp_params):
        """
        Unbounded Regularizer AISTAST 2016 Bobak

        Input parameters
        ----------
        gp_params: parameter for Gaussian Process
        Returns
        -------
        x: recommented point for evaluation
        """

        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=1) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.time_opt = np.hstack((self.time_opt, 0))
            return

        # init a new Gaussian Process
        self.gp = PradaGaussianProcess(gp_params)

        # scale the data before updating the GP
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # Find unique rows of X to avoid GP from breaking

        # Set acquisition function
        start_opt = time.time()

        y_max = self.Y.max()

        self.scalebounds_bk = self.scalebounds.copy()
        self.bounds_bk = self.bounds
        # consider the expansion step after 3 iterations

        if (len(self.Y) % 3) == 0:
            new_radius = 2.0 * self.l_radius
            extra_radius = (new_radius - self.l_radius) / 2

            max_bounds = self.bounds.copy()
            max_bounds[:, 0] = max_bounds[:, 0] - extra_radius
            max_bounds[:, 1] = max_bounds[:, 1] + extra_radius

            # make sure it is within the limit
            if not (self.b_limit_lower is None):
                temp_max_bounds_lower = [
                    np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx])
                    for idx in xrange(self.dim)
                ]
                max_bounds[:, 0] = temp_max_bounds_lower

            if not (self.b_limit_upper is None):
                temp_max_bounds_upper = [
                    np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx])
                    for idx in xrange(self.dim)
                ]
                max_bounds[:, 1] = temp_max_bounds_upper

            self.bounds = np.asarray(max_bounds)

            temp = [(max_bounds[d, :] - self.bounds[d, 0]) * 1.0 /
                    self.max_min_gap[d] for d in xrange(self.dim)]
            self.scalebounds = np.asarray(temp)

        # select the acquisition function
        self.acq['x_bar'] = np.mean(self.bounds)
        self.acq['R'] = np.power(self.l_radius, 1.0 / self.dim)

        self.acq_func = AcquisitionFunction(self.acq)

        # mean of the domain

        #acq['R']

        x_max_scale = acq_max(ac=self.acq_func.acq_kind,
                              gp=self.gp,
                              y_max=y_max,
                              bounds=self.scalebounds,
                              opt_toolbox=self.opt_toolbox)

        #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max)
        #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0])

        # record the optimization time
        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.time_opt = np.hstack((self.time_opt, elapse_opt))

        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max_scale).sum(axis=1) == 0):
            x_max_scale = np.random.uniform(self.scalebounds[:, 0],
                                            self.scalebounds[:, 1],
                                            size=self.scalebounds.shape[0])

        # check if the estimated data point is in the old bound or new
        flagOutside = 0
        for d in xrange(self.dim):
            if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[
                    d] < self.scalebounds_bk[d, 0]:  #outside the old bound
                flagOutside = 1
                self.scalebounds[d, 0] = np.minimum(x_max_scale[d],
                                                    self.scalebounds_bk[d, 0])
                self.scalebounds[d, 1] = np.maximum(x_max_scale[d],
                                                    self.scalebounds_bk[d, 1])

                # now the scalebounds is no longer 0-1

        if flagOutside == 0:  # not outside the old bound
            self.scalebounds = self.scalebounds_bk
        else:  # inside the old bound => recompute bound
            temp = [
                self.scalebounds[d, :] * self.max_min_gap[d] +
                self.bounds_bk[d, 0] for d in xrange(self.dim)
            ]
            if self.dim > 1:
                self.bounds = np.reshape(temp, (self.dim, 2))
            else:
                self.bounds = np.array(temp)

        # compute X in original scale
        temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:,
                                                                              0]
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        # clone the self.X for updating GP
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)])
        self.scalebounds = scalebounds.T
        # evaluate Y using original X

        self.Y_original = np.append(self.Y_original,
                                    self.f(temp_X_new_original))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))

        # for plotting
        self.gp = PradaGaussianProcess(gp_params)
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # update volume and radius
        #self.vol=prod(self.max_min_gap)
        #self.l_radius=np.power(self.vol,1/self.dim)
        self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) /
                               self.dim)
    def maximize_volume_doubling(self, gp_params):
        """
        Volume Doubling, double the volume (e.g., gamma=2) after every 3d evaluations

        Input parameters
        ----------
        gp_params: parameter for Gaussian Process
        Returns
        -------
        x: recommented point for evaluation
        """

        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=1) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.time_opt = np.hstack((self.time_opt, 0))
            return

        # init a new Gaussian Process
        self.gp = PradaGaussianProcess(gp_params)

        # scale the data before updating the GP
        # convert it to scaleX
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # Find unique rows of X to avoid GP from breaking

        # Set acquisition function
        start_opt = time.time()

        y_max = self.Y.max()

        # select the acquisition function
        self.acq_func = AcquisitionFunction(self.acq)

        self.scalebounds_bk = self.scalebounds.copy()
        self.bounds_bk = self.bounds

        # consider the expansion step after 3 iterations

        if (len(self.Y) % 3) == 0:
            new_radius = 2.0 * self.l_radius
            extra_radius = (new_radius - self.l_radius) / 2

            max_bounds = self.bounds.copy()
            max_bounds[:, 0] = max_bounds[:, 0] - extra_radius
            max_bounds[:, 1] = max_bounds[:, 1] + extra_radius

            # make sure it is within the limit
            if not (self.b_limit_lower is None):
                temp_max_bounds_lower = [
                    np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx])
                    for idx in xrange(self.dim)
                ]
                max_bounds[:, 0] = temp_max_bounds_lower

            if not (self.b_limit_upper is None):
                temp_max_bounds_upper = [
                    np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx])
                    for idx in xrange(self.dim)
                ]
                max_bounds[:, 1] = temp_max_bounds_upper

            self.bounds = np.asarray(max_bounds).copy()

            temp = [(max_bounds[d, :] - self.bounds_bk[d, 0]) * 1.0 /
                    self.max_min_gap[d] for d in xrange(self.dim)]
            self.scalebounds = np.asarray(temp)

        # perform standard BO on the new bound (scaled)
        x_max_scale = acq_max(ac=self.acq_func.acq_kind,
                              gp=self.gp,
                              y_max=y_max,
                              bounds=self.scalebounds,
                              opt_toolbox=self.opt_toolbox)

        #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max)
        #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0])

        # record the optimization time
        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.time_opt = np.hstack((self.time_opt, elapse_opt))

        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max_scale).sum(axis=1) == 0):
            x_max_scale = np.random.uniform(self.scalebounds[:, 0],
                                            self.scalebounds[:, 1],
                                            size=self.scalebounds.shape[0])

        # compute X in original scale
        temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:,
                                                                              0]
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        # clone the self.X for updating GP
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)])
        self.scalebounds = scalebounds.T
        # evaluate Y using original X

        self.Y_original = np.append(self.Y_original,
                                    self.f(temp_X_new_original))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))

        # for plotting
        self.gp = PradaGaussianProcess(gp_params)
        ur = unique_rows(self.X)

        try:
            self.gp.fit(self.X[ur], self.Y[ur])
        except:
            print "bug"

        # update volume and radius
        #self.vol=prod(self.max_min_gap)
        #self.l_radius=np.power(self.vol,1/self.dim)
        self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) /
                               self.dim)
    def run_FBO(self, gp_params):
        """
        Main optimization method for filtering strategy for BO.

        Input parameters
        ----------

        gp_params: parameter for Gaussian Process

        Returns
        -------
        x: recommented point for evaluation
        """

        # for random approach
        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=1) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.time_opt = np.hstack((self.time_opt, 0))
            return

        # init a new Gaussian Process
        self.gp = PradaGaussianProcess(gp_params)

        # scale the data before updating the GP
        # convert it to scaleX
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # Set acquisition function
        start_opt = time.time()

        # obtain the maximum on the observed set (for EI)
        y_max = self.Y.max()

        #self.L=self.estimate_L(self.scalebounds)
        # select the acquisition function

        self.acq_func = AcquisitionFunction(self.acq)

        # consider the expansion step

        # finding the maximum over the lower bound
        # mu(x)-kappa x sigma(x)
        mu_acq = {}
        mu_acq['name'] = 'lcb'
        mu_acq['dim'] = self.dim
        mu_acq['kappa'] = 2
        acq_mu = AcquisitionFunction(mu_acq)

        # obtain the argmax(lcb), make sure the scale bound vs original bound
        x_lcb_max = acq_max(ac=acq_mu.acq_kind,
                            gp=self.gp,
                            y_max=y_max,
                            bounds=self.scalebounds,
                            opt_toolbox=self.opt_toolbox)

        # obtain the max(lcb)
        max_lcb = acq_mu.acq_kind(x_lcb_max, gp=self.gp, y_max=y_max)
        max_lcb = np.ravel(max_lcb)

        # finding the region outside the box, that has the ucb > max_lcb
        self.max_min_gap_bk = self.max_min_gap.copy()
        self.bounds_bk = self.bounds.copy()
        self.scalebounds_bk = self.scalebounds.copy()
        self.X_invasion = []

        # the region considered is computed as follows: NewVol~OldVol*T/t
        # alternatively, we compute the radius NewL~Oldl*pow(T/t,1/d)
        new_radius = self.l_radius * np.power(
            self.MaxIter / len(self.Y_original), 1.0 / self.dim)

        # extra proportion
        extra_proportion = new_radius * 1.0 / self.l_radius

        #extra_radius=(new_radius-self.l_radius)/2

        # check if extra radius is negative
        if extra_proportion < 1:
            extra_proportion = 1

        max_bounds = self.bounds.copy()

        # expand half to the lower bound and half to the upper bound, X'_t
        max_bounds[:, 0] = max_bounds[:, 0] - self.max_min_gap * (
            extra_proportion - 1)
        max_bounds[:, 1] = max_bounds[:, 1] + self.max_min_gap * (
            extra_proportion - 1)

        #max_bounds[:,0]=max_bounds[:,0]-extra_radius
        #max_bounds[:,1]=max_bounds[:,1]+extra_radius

        # make sure the max_bounds is within the limit
        if not (self.b_limit_lower is None):
            temp_max_bounds_lower = [
                np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx])
                for idx in xrange(self.dim)
            ]
            max_bounds[:, 0] = temp_max_bounds_lower

        if not (self.b_limit_upper is None):
            temp_max_bounds_upper = [
                np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx])
                for idx in xrange(self.dim)
            ]
            max_bounds[:, 1] = temp_max_bounds_upper

        temp = [
            (max_bounds[d, :] - self.bounds[d, 0]) * 1.0 / self.max_min_gap[d]
            for d in xrange(self.dim)
        ]
        max_bounds_scale = np.asarray(temp)

        # find suitable candidates in new regions
        # ucb(x) > max_lcb st max L(x)

        # new bound in scale space
        # we note that the scalebound will be changed inside this function
        self.max_volume(self.gp, max_bounds_scale, max_lcb)

        #print "new bounds scale"
        #print self.scalebounds

        # perform standard BO on the new bound (scaled)
        x_max_scale = acq_max(ac=self.acq_func.acq_kind,
                              gp=self.gp,
                              y_max=y_max,
                              bounds=self.scalebounds,
                              opt_toolbox=self.opt_toolbox)

        val_acq = self.acq_func.acq_kind(x_max_scale, self.gp, y_max)

        # record the optimization time
        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.time_opt = np.hstack((self.time_opt, elapse_opt))

        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max_scale).sum(axis=1) == 0):
            x_max_scale = np.random.uniform(self.scalebounds[:, 0],
                                            self.scalebounds[:, 1],
                                            size=self.scalebounds.shape[0])

        # check if the estimated data point is in the old bound or new
        flagOutside = 0
        for d in xrange(self.dim):
            if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[
                    d] < self.scalebounds_bk[d, 0]:  #outside the old bound
                flagOutside = 1
                self.scalebounds[d, 0] = np.minimum(x_max_scale[d],
                                                    self.scalebounds_bk[d, 0])
                self.scalebounds[d, 1] = np.maximum(x_max_scale[d],
                                                    self.scalebounds_bk[d, 1])
            else:
                self.scalebounds[d, :] = self.scalebounds_bk[d, :]

                # now the scalebounds is no longer 0-1

        if flagOutside == 0:  # not outside the old bound, use the old bound
            self.scalebounds = self.scalebounds_bk
            self.bounds = self.bounds_bk.copy()
        else:  # outside the old bound => expand the bound as the minimum bound containing the old bound and the selected point
            temp = [
                self.scalebounds[d, :] * self.max_min_gap[d] +
                self.bounds_bk[d, 0] for d in xrange(self.dim)
            ]
            if self.dim > 1:
                self.bounds = np.reshape(temp, (self.dim, 2))
            else:
                self.bounds = np.array(temp)

        self.bounds_list = np.hstack((self.bounds_list, self.bounds))

        # compute X in original scale
        temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:,
                                                                              0]
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        # clone the self.X for updating GP
        self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0]
        temp = np.divide((self.X_original - self.bounds[:, 0]),
                         self.max_min_gap)
        self.X = np.asarray(temp)

        scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)])
        self.scalebounds = scalebounds.T
        # evaluate Y using original X

        self.Y_original = np.append(self.Y_original,
                                    self.f(temp_X_new_original))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))

        # for plotting
        self.gp = PradaGaussianProcess(gp_params)
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # update volume and radius
        #self.vol=prod(self.max_min_gap)
        #self.l_radius=np.power(self.vol,1/self.dim)
        self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) /
                               self.dim)
	def maximize(self,
                 init_points=5,
                 n_iter=25,
                 acq='ucb',
                 kappa=2.576,
                 **gp_params):
		"""
		Main optimization method.

		Parameters
		----------
		:param init_points:
			Number of randomly chosen points to sample the
			target function before fitting the gp.

		:param n_iter:
			Total number of times the process is to repeated. Note that
			currently this methods does not have stopping criteria (due to a
			number of reasons), therefore the total number of points to be
			sampled must be specified.

		:param acq:
			Acquisition function to be used, defaults to Expected Improvement.

		:param gp_params:
			Parameters to be passed to the Scikit-learn Gaussian Process object

		Returns
		-------
		:return: Nothing
		"""
		# Reset timer
		#self.plog.reset_timer()

		# Set acquisition function
		self.util = UtilityFunction(kind=self.acq, kappa=kappa)

		# Initialize x, y and find current y_max
		if not self.initialized:
			#if self.verbose:
				#self.plog.print_header()
			self.init(init_points)

		y_max = self.Y.max()

		self.theta=gp_params['theta']

		# Set parameters if any was passed
		#self.gp.set_params(**gp_params)
		self.gp=PradaMultipleGaussianProcess(**gp_params)

		# Find unique rows of X to avoid GP from breaking
		ur = unique_rows(self.X)
		self.gp.fit(self.X[ur], self.Y[ur])

		# Finding argmax of the acquisition function.
		x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp,
						y_max=y_max,bounds=self.bounds)

		#print "start acq max nlopt"
		#x_max,f_max = acq_max_nlopt(f=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,
							  #bounds=self.bounds)
		#print "end acq max nlopt"

		# Test if x_max is repeated, if it is, draw another one at random
		# If it is repeated, print a warning
		#pwarning = False
		if np.any((self.X - x_max).sum(axis=1) == 0):
			#print "x max uniform random"

			x_max = np.random.uniform(self.bounds[:, 0],
									  self.bounds[:, 1],
									  size=self.bounds.shape[0])
									
		#print "start append X,Y"
		self.X = np.vstack((self.X, x_max.reshape((1, -1))))
		#self.Y = np.append(self.Y, self.f(**dict(zip(self.keys, x_max))))
		self.Y = np.append(self.Y, self.f(x_max))


		#print "end append X,Y"
		#print 'x_max={:f}'.format(x_max[0])

		#print "start fitting GP"

		# Updating the GP.
		ur = unique_rows(self.X)
		self.gp.fit(self.X[ur], self.Y[ur])

		#print "end fitting GP"
		# Update maximum value to search for next probe point.
		if self.Y[-1] > y_max:
			y_max = self.Y[-1]
    def maximize(self,gp_params,kappa=2):
        """
        Main optimization method.

        Input parameters
        ----------

        kappa: parameter for UCB acquisition only.

        gp_params: parameter for Gaussian Process

        Returns
        -------
        x: recommented point for evaluation
        """

        # init a new Gaussian Process
        self.gp=PradaGaussianProcess(gp_params)
        
        # Find unique rows of X to avoid GP from breaking
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])
        

        # Set acquisition function
        start_opt=time.time()

        acq=self.acq
        
        # select the acquisition function
        if acq=='nei':
            self.L=self.estimate_L(self.bounds)
            self.util = AcquisitionFunction(kind=self.acq, L=self.L)
        else:
            if acq=="ucb":
                self.acq_func = AcquisitionFunction(kind=self.acq, kappa=kappa)
            else:
                self.acq_func = AcquisitionFunction(kind=self.acq, kappa=kappa)

        y_max = self.Y.max()
        
        # select the optimization toolbox        
        if self.opt=='nlopt':
            x_max,f_max = acq_max_nlopt(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
        if self.opt=='scipy':
            x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
        if self.opt=='direct':
            x_max = acq_max_direct(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)

        # record the optimization time
        finished_opt=time.time()
        elapse_opt=finished_opt-start_opt
        self.time_opt=np.hstack((self.time_opt,elapse_opt))
        
        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max).sum(axis=1) == 0):

            x_max = np.random.uniform(self.scalebounds[:, 0],
                                      self.scalebounds[:, 1],
                                      size=self.scalebounds.shape[0])
                                     
        # store X                                     
        self.X = np.vstack((self.X, x_max.reshape((1, -1))))

        # compute X in original scale
        temp_X_new_original=x_max*self.max_min_gap+self.bounds[:,0]
        self.X_original=np.vstack((self.X_original, temp_X_new_original))
        # evaluate Y using original X
        self.Y = np.append(self.Y, self.f(temp_X_new_original))
    def maximize_batch_PS(self, gp_params, B=5, kappa=2):
        """
        Finding a batch of points using Peak Suppression approach
        
        Input Parameters
        ----------

        gp_params:          Parameters to be passed to the Gaussian Process class
        
        kappa:              constant value in UCB
              
        Returns
        -------
        X: a batch of [x_1..x_Nt]
        """

        const_liar = self.Y_original.min()

        # Set acquisition function
        #self.acq_func = AcquisitionFunction(kind=self.acq, kappa=kappa)

        y_max = self.Y.max()

        # Set parameters if any was passed
        self.gp = PradaGaussianProcess(gp_params)

        # Find unique rows of X to avoid GP from breaking
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        start_opt = time.time()

        # copy GP, X and Y
        temp_gp = self.gp
        temp_X = self.X
        temp_Y = self.Y

        #store new_x
        new_X = []
        stdPeak = [0] * B
        IsPeak = [0] * B
        for ii in range(B):

            # Finding argmax of the acquisition function.
            x_max = acq_max(ac=self.acq_func.acq_kind,
                            gp=temp_gp,
                            y_max=y_max,
                            bounds=self.scalebounds,
                            opt_toolbox=self.opt_toolbox)

            # Test if x_max is repeated, if it is, draw another one at random
            if np.any((np.abs(temp_X - x_max)).sum(axis=1) < 0.002 *
                      self.dim) | np.isnan(x_max.sum()):
                #x_max = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1],size=self.scalebounds.shape[0])

                IsPeak[ii] = 0
                stdPeak[ii] = 0
                print "reject"
            else:
                IsPeak[ii], stdPeak[ii] = self.check_real_peak(x_max)

            print "IsPeak={:d} std={:.5f}".format(IsPeak[ii], stdPeak[ii])

            if ii == 0:
                new_X = x_max
            else:
                new_X = np.vstack((new_X, x_max.reshape((1, -1))))

            temp_X = np.vstack((temp_X, x_max.reshape((1, -1))))
            temp_Y = np.append(temp_Y, const_liar)

            #temp_gp.fit(temp_X,temp_Y)
            temp_gp.fit_incremental(x_max, np.asarray([const_liar]))
            """
            toplot_bo=copy.deepcopy(self)
            toplot_bo.gp=copy.deepcopy(temp_gp)
            toplot_bo.X=temp_X
            toplot_bo.X_original=[val*self.max_min_gap+self.bounds[:,0] for idx, val in enumerate(temp_X)]
            toplot_bo.X_original=np.asarray(toplot_bo.X_original)
            toplot_bo.Y=temp_Y
            toplot_bo.Y_original=temp_Y*(np.max(self.Y_original)-np.min(self.Y_original))+np.mean(self.Y_original)
            visualization.plot_bo(toplot_bo)
            """

        IsPeak = np.asarray(IsPeak)

        # check if there is no real peak, then pick up the top peak (highest std)

        # rank the peak
        idx = np.sort(stdPeak)

        if np.sum(IsPeak) == 0:
            top_peak = np.argmax(stdPeak)
            new_X = new_X[top_peak]
        else:
            new_X = new_X[IsPeak == 1]

        print new_X

        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.opt_time = np.hstack((self.opt_time, elapse_opt))

        # Updating the GP.
        #new_X=new_X.reshape((-1, self.dim))

        # Test if x_max is repeated, if it is, draw another one at random
        temp_new_X = []
        for idx, val in enumerate(new_X):
            if np.all(
                    np.any(np.abs(self.X - val) > 0.02,
                           axis=1)):  # check if a data point is already taken
                temp_new_X = np.append(temp_new_X, val)

        if len(temp_new_X) == 0:
            temp_new_X = np.zeros((1, self.dim))
            for idx in range(0, self.dim):
                temp_new_X[0,
                           idx] = np.random.uniform(self.scalebounds[idx, 0],
                                                    self.scalebounds[idx,
                                                                     1], 1)
        else:
            temp_new_X = temp_new_X.reshape((-1, self.dim))

        self.X = np.vstack((self.X, temp_new_X))

        # convert back to original scale
        temp_X_new_original = [
            val * self.max_min_gap + self.bounds[:, 0]
            for idx, val in enumerate(temp_new_X)
        ]
        temp_X_new_original = np.asarray(temp_X_new_original)
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        for idx, val in enumerate(temp_X_new_original):
            self.Y_original = np.append(self.Y_original, self.f(val))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))
        self.NumPoints = np.append(self.NumPoints,
                                   temp_X_new_original.shape[0])

        print "#Batch={:d} f_max={:.4f}".format(temp_X_new_original.shape[0],
                                                self.Y_original.max())
    def maximize_batch_CL_incremental(self, gp_params, B=5):
        """
        Finding a batch of points using Constant Liar approach
        
        Input Parameters
        ----------

        gp_params:          Parameters to be passed to the Gaussian Process class
        
        kappa:              constant value in UCB
              
        Returns
        -------
        X: a batch of [x_1..x_Nt]
        """

        self.NumPoints = np.append(self.NumPoints, B)

        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=B) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X

            #self.Y = np.append(self.Y, self.f(temp_X_new_original))
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.opt_time = np.hstack((self.opt_time, 0))
            return

        #const_liar=self.Y.mean()
        #const_liar=self.Y_original.min()
        #const_liar=self.Y.max()

        # Set acquisition function
        self.acq_func = AcquisitionFunction(self.acq)

        y_max = self.Y.max()

        # Set parameters if any was passed
        self.gp = PradaGaussianProcess(gp_params)

        # Find unique rows of X to avoid GP from breaking
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        start_opt = time.time()

        # copy GP, X and Y
        temp_gp = copy.deepcopy(self.gp)
        temp_X = self.X
        temp_Y = self.Y
        #temp_Y_original=self.Y_original

        #store new_x
        new_X = []
        for ii in range(B):

            # Finding argmax of the acquisition function.
            x_max = acq_max(ac=self.acq_func.acq_kind,
                            gp=temp_gp,
                            y_max=y_max,
                            bounds=self.scalebounds)

            # Test if x_max is repeated, if it is, draw another one at random
            if np.any(
                    np.any(np.abs(self.X - x_max) < 0.02,
                           axis=1)):  # check if a data point is already taken
                x_max = np.random.uniform(self.scalebounds[:, 0],
                                          self.scalebounds[:, 1],
                                          size=self.scalebounds.shape[0])

            if ii == 0:
                new_X = x_max
            else:
                new_X = np.vstack((new_X, x_max.reshape((1, -1))))

            const_liar = temp_gp.predict(x_max, eval_MSE=true)

            #temp_X= np.vstack((temp_X, x_max.reshape((1, -1))))
            #temp_Y = np.append(temp_Y, const_liar )

            #temp_gp.fit(temp_X,temp_Y)

            # update the Gaussian Process and thus the acquisition function
            #temp_gp.compute_incremental_var(temp_X,x_max)
            temp_gp.fit_incremental(x_max, np.asarray([const_liar]))

        # Updating the GP.
        new_X = new_X.reshape((B, -1))

        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.opt_time = np.hstack((self.opt_time, elapse_opt))

        #print new_X

        self.X = np.vstack((self.X, new_X))

        # convert back to original scale
        temp_X_new_original = [
            val * self.max_min_gap + self.bounds[:, 0]
            for idx, val in enumerate(new_X)
        ]
        temp_X_new_original = np.asarray(temp_X_new_original)
        self.X_original = np.vstack((self.X_original, temp_X_new_original))

        for idx, val in enumerate(temp_X_new_original):
            self.Y_original = np.append(self.Y_original, self.f(val))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))
    def maximize(self, gp_params, kappa=2):
        """
        Main optimization method.

        Input parameters
        ----------

        kappa: parameter for UCB acquisition only.

        gp_params: parameter for Gaussian Process

        Returns
        -------
        x: recommented point for evaluation
        """

        if self.acq['name'] == 'random':
            x_max = [
                np.random.uniform(x[0], x[1], size=1) for x in self.bounds
            ]
            x_max = np.asarray(x_max)
            x_max = x_max.T
            self.X_original = np.vstack((self.X_original, x_max))
            # evaluate Y using original X

            #self.Y = np.append(self.Y, self.f(temp_X_new_original))
            self.Y_original = np.append(self.Y_original, self.f(x_max))

            # update Y after change Y_original
            self.Y = (self.Y_original - np.mean(self.Y_original)) / (
                np.max(self.Y_original) - np.min(self.Y_original))

            self.time_opt = np.hstack((self.time_opt, 0))
            return

        # init a new Gaussian Process
        self.gp = PradaGaussianProcess(gp_params)

        # Find unique rows of X to avoid GP from breaking
        ur = unique_rows(self.X)
        self.gp.fit(self.X[ur], self.Y[ur])

        # Set acquisition function
        start_opt = time.time()

        acq = self.acq
        y_max = self.Y.max()

        #self.L=self.estimate_L(self.scalebounds)
        # select the acquisition function
        if acq['name'] == 'nei':
            self.L = self.estimate_L(self.scalebounds)
            self.acq_func = AcquisitionFunction(kind=self.acq, L=self.L)
        else:
            self.acq_func = AcquisitionFunction(self.acq)

            if acq['name'] == "ei_mu":
                #find the maximum in the predictive mean
                mu_acq = {}
                mu_acq['name'] = 'mu'
                mu_acq['dim'] = self.dim
                acq_mu = AcquisitionFunction(mu_acq)
                x_mu_max = acq_max(ac=acq_mu.acq_kind,
                                   gp=self.gp,
                                   y_max=y_max,
                                   bounds=self.scalebounds,
                                   opt_toolbox=self.opt_toolbox)
                # set y_max = mu_max
                y_max = acq_mu.acq_kind(x_mu_max, gp=self.gp, y_max=y_max)

        x_max = acq_max(ac=self.acq_func.acq_kind,
                        gp=self.gp,
                        y_max=y_max,
                        bounds=self.scalebounds,
                        opt_toolbox=self.opt_toolbox)

        val_acq = self.acq_func.acq_kind(x_max, self.gp, y_max)
        #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0])
        # check the value alpha(x_max)==0
        #if val_acq<0.0001:
        #self.stop_flag=1
        #return

        # select the optimization toolbox
        """      
        if self.opt=='nlopt':
            x_max,f_max = acq_max_nlopt(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
        if self.opt=='scipy':
            
        if self.opt=='direct':
            x_max = acq_max_direct(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
        """

        # record the optimization time
        finished_opt = time.time()
        elapse_opt = finished_opt - start_opt
        self.time_opt = np.hstack((self.time_opt, elapse_opt))

        # Test if x_max is repeated, if it is, draw another one at random
        if np.any((self.X - x_max).sum(axis=1) == 0):

            x_max = np.random.uniform(self.scalebounds[:, 0],
                                      self.scalebounds[:, 1],
                                      size=self.scalebounds.shape[0])

        # store X
        self.X = np.vstack((self.X, x_max.reshape((1, -1))))

        # compute X in original scale
        temp_X_new_original = x_max * self.max_min_gap + self.bounds[:, 0]
        self.X_original = np.vstack((self.X_original, temp_X_new_original))
        # evaluate Y using original X

        #self.Y = np.append(self.Y, self.f(temp_X_new_original))
        self.Y_original = np.append(self.Y_original,
                                    self.f(temp_X_new_original))

        # update Y after change Y_original
        self.Y = (self.Y_original - np.mean(self.Y_original)) / (
            np.max(self.Y_original) - np.min(self.Y_original))
    def maximize(self,gp_params):
        """
        Main optimization method.

        Input parameters
        ----------
        gp_params: parameter for Gaussian Process

        Returns
        -------
        x: recommented point for evaluation
        """

        if self.stop_flag==1:
            return
            
        if self.acq['name']=='random':
            x_max = [np.random.uniform(x[0], x[1], size=1) for x in self.scalebounds]
            x_max=np.asarray(x_max)
            x_max=x_max.T
            self.X_original=np.vstack((self.X_original, x_max))
            # evaluate Y using original X
            
            self.Y_original = np.append(self.Y_original, self.f(x_max))
            
            # update Y after change Y_original
            self.Y=(self.Y_original-np.mean(self.Y_original))/np.std(self.Y_original)
            
            self.time_opt=np.hstack((self.time_opt,0))
            return         

        # init a new Gaussian Process
        self.gp=PradaGaussianProcess(gp_params)
        if self.gp.KK_x_x_inv ==[]:
            # Find unique rows of X to avoid GP from breaking
            ur = unique_rows(self.X)
            self.gp.fit(self.X[ur], self.Y[ur])

 
        acq=self.acq

        if acq['debug']==1:
            logmarginal=self.gp.log_marginal_lengthscale(gp_params['theta'],gp_params['noise_delta'])
            print(gp_params['theta'])
            print("log marginal before optimizing ={:.4f}".format(logmarginal))
            self.logmarginal=logmarginal
                
            if logmarginal<-999999:
                logmarginal=self.gp.log_marginal_lengthscale(gp_params['theta'],gp_params['noise_delta'])

        if self.optimize_gp==1 and len(self.Y)%2*self.dim==0 and len(self.Y)>5*self.dim:

            print("Initial length scale={}".format(gp_params['theta']))
            newtheta = self.gp.optimize_lengthscale(gp_params['theta'],gp_params['noise_delta'],self.scalebounds)
            gp_params['theta']=newtheta
            print("New length scale={}".format(gp_params['theta']))

            # init a new Gaussian Process after optimizing hyper-parameter
            self.gp=PradaGaussianProcess(gp_params)
            # Find unique rows of X to avoid GP from breaking
            ur = unique_rows(self.X)
            self.gp.fit(self.X[ur], self.Y[ur])

            
        # Modify search space based on selected method
        if self.expandSS=='expandBoundsDDB_MAP':
			self.expandBoundsDDB_MAP()
        if self.expandSS=='expandBoundsDDB_FB':
			self.expandBoundsDDB_FB()            
        if self.expandSS=='expandBoundsFiltering':
            self.expandBoundsFiltering()
        if self.expandSS=='volumeDoubling' and len(self.Y)%3*self.dim==0:
            self.volumeDoubling()
        # Prevent bounds from breaching maximum limit
        for d in range(0,self.dim):
            if self.scalebounds[d,0]<0:
                print('Lower bound of {} in dimention {} exceeded minimum bound of {}. Scaling up.'.format(self.scalebounds[d,0],d,0))
                self.scalebounds[d,0]=0
                print('bound set to {}'.format(self.scalebounds))
            if self.scalebounds[d,1]>max_bound_size:
                print('Upper bound of {} in dimention {} exceeded maximum bound of {}. Scaling down.'.format(self.scalebounds[d,1],d,max_bound_size))
                self.scalebounds[d,1]=max_bound_size
                self.scalebounds[d,0]=min(self.scalebounds[d,0],self.scalebounds[d,1]-np.sqrt(3*self.gp.lengthscale))
                print('bound set to {}'.format(self.scalebounds))
        
        # Set acquisition function
        start_opt=time.time()

        y_max = self.Y.max()
        
        if acq['name'] in ['consensus','mes']: 
            ucb_acq_func={}
            ucb_acq_func['name']='ucb'
            ucb_acq_func['kappa']=np.log(len(self.Y))
            ucb_acq_func['dim']=self.dim
            ucb_acq_func['scalebounds']=self.scalebounds
        
            myacq=AcquisitionFunction(ucb_acq_func)
            xt_ucb = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
            
            xstars=[]
            xstars.append(xt_ucb)
            
            ei_acq_func={}
            ei_acq_func['name']='ei'
            ei_acq_func['dim']=self.dim
            ei_acq_func['scalebounds']=self.scalebounds
        
            myacq=AcquisitionFunction(ei_acq_func)
            xt_ei = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
            xstars.append(xt_ei)
                 
            
            pes_acq_func={}
            pes_acq_func['name']='pes'
            pes_acq_func['dim']=self.dim
            pes_acq_func['scalebounds']=self.scalebounds
        
            myacq=AcquisitionFunction(pes_acq_func)
            xt_pes = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds)
            xstars.append(xt_pes)
            
            
            self.xstars=xstars            
            
        if acq['name']=='vrs':
            print("please call the maximize_vrs function")
            return
                      
        if 'xstars' not in globals():
            xstars=[]
            
        self.xstars=xstars

        self.acq['xstars']=xstars
        self.acq['WW']=False
        self.acq['WW_dim']=False
        self.acq_func = AcquisitionFunction(self.acq,self.bb_function)

        if acq['name']=="ei_mu":
            #find the maximum in the predictive mean
            mu_acq={}
            mu_acq['name']='mu'
            mu_acq['dim']=self.dim
            acq_mu=AcquisitionFunction(mu_acq)
            x_mu_max = acq_max(ac=acq_mu.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds,opt_toolbox=self.opt_toolbox)
            # set y_max = mu_max
            y_max=acq_mu.acq_kind(x_mu_max,gp=self.gp, y_max=y_max)

        
        x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds,opt_toolbox=self.opt_toolbox,seeds=self.xstars)

        if acq['name']=='consensus' and acq['debug']==1: # plot the x_max and xstars
            fig=plt.figure(figsize=(5, 5))

            plt.scatter(xt_ucb[0],xt_ucb[1],marker='s',color='g',s=200,label='Peak')
            plt.scatter(xt_ei[0],xt_ei[1],marker='s',color='k',s=200,label='Peak')
            plt.scatter(x_max[0],x_max[1],marker='*',color='r',s=300,label='Peak')
            plt.xlim(0,1)
            plt.ylim(0,1)
            strFileName="acquisition_functions_debug.eps"
            fig.savefig(strFileName, bbox_inches='tight')

        if acq['name']=='vrs' and acq['debug']==1: # plot the x_max and xstars
            fig=plt.figure(figsize=(5, 5))

            plt.scatter(xt_ucb[0],xt_ucb[1],marker='s',color='g',s=200,label='Peak')
            plt.scatter(xt_ei[0],xt_ei[1],marker='s',color='k',s=200,label='Peak')
            plt.scatter(x_max[0],x_max[1],marker='*',color='r',s=300,label='Peak')
            plt.xlim(0,1)
            plt.ylim(0,1)
            strFileName="vrs_acquisition_functions_debug.eps"
            #fig.savefig(strFileName, bbox_inches='tight')
            
            
        val_acq=self.acq_func.acq_kind(x_max,self.gp,y_max)
        #print x_max
        #print val_acq
        if self.stopping_criteria!=0 and val_acq<self.stopping_criteria:
            val_acq=self.acq_func.acq_kind(x_max,self.gp,y_max)

            self.stop_flag=1
            print("Stopping Criteria is violated. Stopping Criteria is {:.15f}".format(self.stopping_criteria))
        
        
        self.alpha_Xt= np.append(self.alpha_Xt,val_acq)
        
        mean,var=self.gp.predict(x_max, eval_MSE=True)
        var.flags['WRITEABLE']=True
        var[var<1e-20]=0
        #self.Tau_Xt= np.append(self.Tau_Xt,val_acq/var)
       
        # record the optimization time
        finished_opt=time.time()
        elapse_opt=finished_opt-start_opt
        self.time_opt=np.hstack((self.time_opt,elapse_opt))
        
        # store X                                     
        self.X = np.vstack((self.X, x_max.reshape((1, -1))))

        # evaluate Y using original X
        self.Y_original = np.append(self.Y_original, self.f(x_max))
        
        # update Y after change Y_original
        self.Y=(self.Y_original-np.mean(self.Y_original))/np.std(self.Y_original)
        
        if self.gp.flagIncremental==1:
            self.gp.fit_incremental(x_max,self.Y[-1])
#        if (self.acq['name']=='ei_regularizerH') or (self.acq['name']=='ei_regularizerQ'):
#            self.scalebounds[:,0]=self.scalebounds[:,0]+1
#            self.scalebounds[:,1]=self.scalebounds[:,1]-1
#        self.acq['scalebounds']=self.scalebounds
        self.experiment_num=self.experiment_num+1
Example #23
0
        def compute_log_marginal(X, lengthscale, noise_delta):
            """
            def ARD_dist_func(A,B,length_scale):
                mysum=0
                for idx,val in enumerate(length_scale):
                    mysum=mysum+((A[idx]-B[idx])**2)/val
                    #print mysum
                dist=np.exp(-mysum)
                return dist
            """
            # compute K
            ur = unique_rows(self.X)
            myX = self.X[ur]
            myY = self.Y[ur]
            #myX=self.X
            #myY=self.Y
            if self.flagOptimizeHyperFirst == 0:
                if self.kernel_name == 'SE':
                    self.Euc_dist_X_X = euclidean_distances(myX, myX)
                    KK = np.exp(-np.square(self.Euc_dist_X_X) /
                                (2 * np.square(lengthscale))) + np.eye(
                                    len(myX)) * self.noise_delta
                else:
                    KK = pdist(
                        myX, lambda a, b: self.kernel_dist(a, b, lengthscale))
                    KK = squareform(KK)
                    KK = KK + np.eye(myX.shape[0]) * (1 + noise_delta)
                self.flagOptimizeHyperFirst = 1
            else:
                if self.kernel_name == 'SE':
                    KK = np.exp(-np.square(self.Euc_dist_X_X) /
                                (2 * np.square(lengthscale))) + np.eye(
                                    len(myX)) * self.noise_delta
                else:
                    KK = pdist(
                        myX, lambda a, b: self.kernel_dist(a, b, lengthscale))
                    KK = squareform(KK)
                    KK = KK + np.eye(myX.shape[0]) * (1 + noise_delta)

            try:
                temp_inv = np.linalg.solve(KK, np.eye(KK.shape[0]))
            except:  # singular
                return -np.inf

            #logmarginal=-0.5*np.dot(self.Y.T,temp_inv)-0.5*np.log(np.linalg.det(KK+noise_delta))-0.5*len(X)*np.log(2*3.14)
            first_term = -0.5 * np.dot(myY.T, np.dot(temp_inv, myY))

            # if the matrix is too large, we randomly select a part of the data for fast computation
            if KK.shape[0] > 200:
                idx = np.random.permutation(KK.shape[0])
                idx = idx[:200]
                KK = KK[np.ix_(idx, idx)]
            #Wi, LW, LWi, W_logdet = pdinv(KK)
            #sign,W_logdet2=np.linalg.slogdet(KK)
            chol = spla.cholesky(KK, lower=True)
            W_logdet = np.sum(np.log(np.diag(chol)))
            # Uses the identity that log det A = log prod diag chol A = sum log diag chol A

            #second_term=-0.5*W_logdet2
            second_term = -0.5 * W_logdet
            #print "first term ={:.4f} second term ={:.4f}".format(np.asscalar(first_term),np.asscalar(second_term))

            logmarginal = first_term + second_term - 0.5 * len(myY) * np.log(
                2 * 3.14)
            #print("lengthscale={}, likelihood={}".format(self.lengthscale,logmarginal))
            if np.isnan(np.asscalar(logmarginal)) == True:
                print(myY)
                print "theta={:s} first term ={:.4f} second  term ={:.4f}".format(
                    lengthscale, np.asscalar(first_term),
                    np.asscalar(second_term))
                #print temp_det

            return np.asscalar(logmarginal)