Beispiel #1
0
 def time_stationary_ego(self, theta, repeated_domain, iterations, data, params, lbfgs_parameters, num_multistarts,threadid, sigma_2=0, plot = True):
     res = numpy.zeros((iterations))
     ei = numpy.zeros((iterations))
     idx = params[0]
     low = params[1]
     high = params[2]
     theta[2] += sigma_2
     print(theta)
     cov = SquareExponential(theta)
     gaussian_process = IntegratedGaussianProcess(cov, data, *params)
     ts = numpy.random.uniform(low,high,20)
     for i in range(iterations):
         print('Thread: '+ str( threadid) + ' at : ' + str(100*i/iterations) + '%')
         #find new point to sample
         cora_ei_eval = ExpectedImprovement(gaussian_process, t=ts[i%20])
         ei_optimizer = LBFGSBOptimizer(repeated_domain, cora_ei_eval, lbfgs_parameters)
         best_point, function_argument_list, starts = self.multistart_expected_improvement_optimization(ei_optimizer, num_multistarts)
         best_point[:,1] = ts[i%20]#random time corresponds to rl testcase
         ei[i] = cora_ei_eval.evaluate_at_point_list(best_point)
         #evaluate point
         data = self.append_evaluation(data, best_point, self.noiselvl)
         #fit new gaussian process to data
         #theta =self.fit_hyperparameters(data)
         cov = SquareExponential(theta)
         gaussian_process = IntegratedGaussianProcess(cov, data, *params)
         best_gp_mean = self.get_optimum(gaussian_process)
         points_sampled = data.points_sampled
         function_vals = data.points_sampled_value
         if(plot == True):
             print("plotting")
             self.plot_estimate(i, low[0], high[0], gaussian_process, cora_ei_eval, points_sampled, function_vals, theta, function_argument_list, starts, best_gp_mean ,threadid)
         res[i]= best_gp_mean[0]
     return [res, ei]
    def test_multistart_qei_expected_improvement_dfo(self):
        """Check that multistart optimization (BFGS) can find the optimum point to sample (using 2-EI)."""
        numpy.random.seed(7860)
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20))
        domain, gaussian_process = self.gp_test_environments[index]

        tolerance = 6.0e-5
        num_multistarts = 3

        # Expand the domain so that we are definitely not doing constrained optimization
        expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 3.0)] *
                                              self.dim)
        num_to_sample = 2
        repeated_domain = RepeatedDomain(num_to_sample, expanded_domain)

        num_mc_iterations = 100000
        # Just any random point that won't be optimal
        points_to_sample = repeated_domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process,
                                      points_to_sample,
                                      num_mc_iterations=num_mc_iterations)
        # Compute EI and its gradient for the sake of comparison
        ei_initial = ei_eval.compute_expected_improvement()

        ei_optimizer = LBFGSBOptimizer(repeated_domain, ei_eval,
                                       self.BFGS_parameters)
        best_point = multistart_expected_improvement_optimization(
            ei_optimizer, num_multistarts, num_to_sample)

        # Check that gradients are "small" or on border. MC is very inaccurate near 0, so use finite difference
        # gradient instead.
        ei_eval.current_point = best_point
        ei_final = ei_eval.compute_expected_improvement()

        finite_diff_grad = numpy.zeros(best_point.shape)
        h_value = 0.00001
        for i in range(best_point.shape[0]):
            for j in range(best_point.shape[1]):
                best_point[i, j] += h_value
                ei_eval.current_point = best_point
                ei_upper = ei_eval.compute_expected_improvement()
                best_point[i, j] -= 2 * h_value
                ei_eval.current_point = best_point
                ei_lower = ei_eval.compute_expected_improvement()
                best_point[i, j] += h_value
                finite_diff_grad[i, j] = (ei_upper - ei_lower) / (2 * h_value)

        self.assert_vector_within_relative(finite_diff_grad,
                                           numpy.zeros(finite_diff_grad.shape),
                                           tolerance)

        # Check that output is in the domain
        assert repeated_domain.check_point_inside(best_point) is True

        # Since we didn't really converge to the optimal EI (too costly), do some other sanity checks
        # EI should have improved
        assert ei_final >= ei_initial
Beispiel #3
0
    def test_1d_analytic_ei_edge_cases(self):
        """Test cases where analytic EI would attempt to compute 0/0 without variance lower bounds."""
        base_coord = numpy.array([0.5])
        point1 = SamplePoint(base_coord, -1.809342, 0)
        point2 = SamplePoint(base_coord * 2.0, -1.09342, 0)

        # First a symmetric case: only one historical point
        data = HistoricalData(base_coord.size, [point1])

        hyperparameters = numpy.array([0.2, 0.3])
        covariance = SquareExponential(hyperparameters)
        gaussian_process = GaussianProcess(covariance, data)

        point_to_sample = base_coord
        ei_eval = ExpectedImprovement(gaussian_process, point_to_sample)

        ei = ei_eval.compute_expected_improvement()
        grad_ei = ei_eval.compute_grad_expected_improvement()
        self.assert_scalar_within_relative(ei, 0.0, 1.0e-15)
        self.assert_vector_within_relative(grad_ei, numpy.zeros(grad_ei.shape), 1.0e-15)

        shifts = (1.0e-15, 4.0e-11, 3.14e-6, 8.89e-1, 2.71)
        self._check_ei_symmetry(ei_eval, point_to_sample, shifts)

        # Now introduce some asymmetry with a second point
        # Right side has a larger objetive value, so the EI minimum
        # is shifted *slightly* to the left of best_so_far.
        gaussian_process.add_sampled_points([point2])
        shift = 3.0e-12
        ei_eval = ExpectedImprovement(gaussian_process, point_to_sample - shift)
        ei = ei_eval.compute_expected_improvement()
        grad_ei = ei_eval.compute_grad_expected_improvement()
        self.assert_scalar_within_relative(ei, 0.0, 1.0e-15)
        self.assert_vector_within_relative(grad_ei, numpy.zeros(grad_ei.shape), 1.0e-15)
    def test_multistart_analytic_expected_improvement_optimization(self):
        """Check that multistart optimization (gradient descent) can find the optimum point to sample (using 1D analytic EI)."""
        numpy.random.seed(3148)
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20))
        domain, gaussian_process = self.gp_test_environments[index]

        max_num_steps = 200  # this is generally *too few* steps; we configure it this way so the test will run quickly
        max_num_restarts = 5
        num_steps_averaged = 0
        gamma = 0.2
        pre_mult = 1.5
        max_relative_change = 1.0
        tolerance = 1.0e-7
        gd_parameters = GradientDescentParameters(
            max_num_steps,
            max_num_restarts,
            num_steps_averaged,
            gamma,
            pre_mult,
            max_relative_change,
            tolerance,
        )
        num_multistarts = 3

        points_to_sample = domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process, points_to_sample)

        # expand the domain so that we are definitely not doing constrained optimization
        expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 2.0)] *
                                              self.dim)

        num_to_sample = 1
        repeated_domain = RepeatedDomain(ei_eval.num_to_sample,
                                         expanded_domain)
        ei_optimizer = GradientDescentOptimizer(repeated_domain, ei_eval,
                                                gd_parameters)
        best_point = multistart_expected_improvement_optimization(
            ei_optimizer, num_multistarts, num_to_sample)

        # Check that gradients are small
        ei_eval.current_point = best_point
        gradient = ei_eval.compute_grad_expected_improvement()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(gradient.shape),
                                           tolerance)

        # Check that output is in the domain
        assert repeated_domain.check_point_inside(best_point) is True
Beispiel #5
0
 def optimize(self, all_x):
     """
     :param all_x:
     :return: (best_point, found_point_successfully)
     """
     ei_evaluator = ExpectedImprovement(self._gp)
     ei_vals = numpy.zeros(len(all_x))
     for i in range(len(ei_vals)):
         ei_evaluator.set_current_point(all_x[i, :].reshape((1, -1)))
         print ei_evaluator.num_to_sample
         ei_vals[i] = ei_evaluator.compute_expected_improvement()
     best_ei = numpy.amax(ei_vals)
     if best_ei > 0:
         return all_x[numpy.argmax(best_ei), :], True
     else:
         return all_x[numpy.random.randint(low=0, high=len(best_ei), size=1
                                           ), :], False
Beispiel #6
0
    def test_evaluate_ei_at_points(self):
        """Check that ``evaluate_expected_improvement_at_point_list`` computes and orders results correctly (using 1D analytic EI)."""
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 5))
        domain, gaussian_process = self.gp_test_environments[index]

        points_to_sample = domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process, points_to_sample)

        num_to_eval = 10
        # Add in a newaxis to make num_to_sample explicitly 1
        points_to_evaluate = domain.generate_uniform_random_points_in_domain(num_to_eval)[:, numpy.newaxis, :]

        test_values = ei_eval.evaluate_at_point_list(points_to_evaluate)

        for i, value in enumerate(test_values):
            ei_eval.current_point = points_to_evaluate[i, ...]
            truth = ei_eval.compute_expected_improvement()
            assert value == truth
    def test_multistart_analytic_expected_improvement_optimization(self):
        """Check that multistart optimization (gradient descent) can find the optimum point to sample (using 1D analytic EI)."""
        numpy.random.seed(3148)
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20))
        domain, gaussian_process = self.gp_test_environments[index]

        max_num_steps = 200  # this is generally *too few* steps; we configure it this way so the test will run quickly
        max_num_restarts = 5
        num_steps_averaged = 0
        gamma = 0.2
        pre_mult = 1.5
        max_relative_change = 1.0
        tolerance = 1.0e-7
        gd_parameters = GradientDescentParameters(
            max_num_steps,
            max_num_restarts,
            num_steps_averaged,
            gamma,
            pre_mult,
            max_relative_change,
            tolerance,
        )
        num_multistarts = 3

        points_to_sample = domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process, points_to_sample)

        # expand the domain so that we are definitely not doing constrained optimization
        expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 2.0)] * self.dim)

        num_to_sample = 1
        repeated_domain = RepeatedDomain(ei_eval.num_to_sample, expanded_domain)
        ei_optimizer = GradientDescentOptimizer(repeated_domain, ei_eval, gd_parameters)
        best_point = multistart_expected_improvement_optimization(ei_optimizer, num_multistarts, num_to_sample)

        # Check that gradients are small
        ei_eval.current_point = best_point
        gradient = ei_eval.compute_grad_expected_improvement()
        self.assert_vector_within_relative(gradient, numpy.zeros(gradient.shape), tolerance)

        # Check that output is in the domain
        assert repeated_domain.check_point_inside(best_point) is True
Beispiel #8
0
    def test_multistart_monte_carlo_expected_improvement_optimization(self):
        """Check that multistart optimization (gradient descent) can find the optimum point to sample (using 2-EI)."""
        numpy.random.seed(7858)  # TODO(271): Monte Carlo only works for this seed
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20))
        domain, gaussian_process = self.gp_test_environments[index]

        max_num_steps = 75  # this is *too few* steps; we configure it this way so the test will run quickly
        max_num_restarts = 5
        num_steps_averaged = 50
        gamma = 0.2
        pre_mult = 1.5
        max_relative_change = 1.0
        tolerance = 3.0e-2  # really large tolerance b/c converging with monte-carlo (esp in Python) is expensive
        gd_parameters = GradientDescentParameters(
            max_num_steps,
            max_num_restarts,
            num_steps_averaged,
            gamma,
            pre_mult,
            max_relative_change,
            tolerance,
        )
        num_multistarts = 2

        # Expand the domain so that we are definitely not doing constrained optimization
        expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 2.0)] * self.dim)
        num_to_sample = 2
        repeated_domain = RepeatedDomain(num_to_sample, expanded_domain)

        num_mc_iterations = 10000
        # Just any random point that won't be optimal
        points_to_sample = repeated_domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process, points_to_sample, num_mc_iterations=num_mc_iterations)
        # Compute EI and its gradient for the sake of comparison
        ei_initial = ei_eval.compute_expected_improvement(force_monte_carlo=True)  # TODO(271) Monte Carlo only works for this seed
        grad_ei_initial = ei_eval.compute_grad_expected_improvement()

        ei_optimizer = GradientDescentOptimizer(repeated_domain, ei_eval, gd_parameters)
        best_point = multistart_expected_improvement_optimization(ei_optimizer, num_multistarts, num_to_sample)

        # Check that gradients are "small"
        ei_eval.current_point = best_point
        ei_final = ei_eval.compute_expected_improvement(force_monte_carlo=True)  # TODO(271) Monte Carlo only works for this seed
        grad_ei_final = ei_eval.compute_grad_expected_improvement()
        self.assert_vector_within_relative(grad_ei_final, numpy.zeros(grad_ei_final.shape), tolerance)

        # Check that output is in the domain
        assert repeated_domain.check_point_inside(best_point) is True

        # Since we didn't really converge to the optimal EI (too costly), do some other sanity checks
        # EI should have improved
        assert ei_final >= ei_initial

        # grad EI should have improved
        for index in numpy.ndindex(grad_ei_final.shape):
            assert numpy.fabs(grad_ei_final[index]) <= numpy.fabs(grad_ei_initial[index])
    def test_multistart_qei_expected_improvement_dfo(self):
        """Check that multistart optimization (BFGS) can find the optimum point to sample (using 2-EI)."""
        numpy.random.seed(7860)
        index = numpy.argmax(numpy.greater_equal(self.num_sampled_list, 20))
        domain, gaussian_process = self.gp_test_environments[index]

        tolerance = 6.0e-5
        num_multistarts = 3

        # Expand the domain so that we are definitely not doing constrained optimization
        expanded_domain = TensorProductDomain([ClosedInterval(-4.0, 3.0)] * self.dim)
        num_to_sample = 2
        repeated_domain = RepeatedDomain(num_to_sample, expanded_domain)

        num_mc_iterations = 100000
        # Just any random point that won't be optimal
        points_to_sample = repeated_domain.generate_random_point_in_domain()
        ei_eval = ExpectedImprovement(gaussian_process, points_to_sample, num_mc_iterations=num_mc_iterations)
        # Compute EI and its gradient for the sake of comparison
        ei_initial = ei_eval.compute_expected_improvement()

        ei_optimizer = LBFGSBOptimizer(repeated_domain, ei_eval, self.BFGS_parameters)
        best_point = multistart_expected_improvement_optimization(ei_optimizer, num_multistarts, num_to_sample)

        # Check that gradients are "small" or on border. MC is very inaccurate near 0, so use finite difference
        # gradient instead.
        ei_eval.current_point = best_point
        ei_final = ei_eval.compute_expected_improvement()

        finite_diff_grad = numpy.zeros(best_point.shape)
        h_value = 0.00001
        for i in range(best_point.shape[0]):
            for j in range(best_point.shape[1]):
                best_point[i, j] += h_value
                ei_eval.current_point = best_point
                ei_upper = ei_eval.compute_expected_improvement()
                best_point[i, j] -= 2 * h_value
                ei_eval.current_point = best_point
                ei_lower = ei_eval.compute_expected_improvement()
                best_point[i, j] += h_value
                finite_diff_grad[i, j] = (ei_upper - ei_lower) / (2 * h_value)

        self.assert_vector_within_relative(finite_diff_grad, numpy.zeros(finite_diff_grad.shape), tolerance)

        # Check that output is in the domain
        assert repeated_domain.check_point_inside(best_point) is True

        # Since we didn't really converge to the optimal EI (too costly), do some other sanity checks
        # EI should have improved
        assert ei_final >= ei_initial
Beispiel #10
0
def optimize_with_ego(gp, domain_bounds, num_multistart):
    expected_improvement_evaluator = ExpectedImprovement(gp)
    search_domain = pythonTensorProductDomain(
        [ClosedInterval(bound[0], bound[1]) for bound in domain_bounds])
    start_points = search_domain.generate_uniform_random_points_in_domain(
        num_multistart)
    min_negative_ei = numpy.inf

    def negative_ego_func(x):
        expected_improvement_evaluator.set_current_point(x.reshape((1, -1)))
        return -1.0 * expected_improvement_evaluator.compute_expected_improvement(
        )

    for start_point in start_points:
        x, f = bfgs_optimization(start_point, negative_ego_func, domain_bounds)
        if min_negative_ei > f:
            min_negative_ei = f
            point_to_sample = x
    return point_to_sample, -min_negative_ei
Beispiel #11
0
    def test_expected_improvement_and_gradient(self):
        """Test EI by comparing the vectorized and "naive" versions.

        With the same RNG state, these two functions should return identical output.
        We use a fairly low number of monte-carlo iterations since we are not
        trying to converge; just check for consistency.

        .. Note:: this is not a particularly good test. It relies on the "naive"
          version being easier to verify manually and only checks for consistency
          between the naive and vectorized versions.

        """
        num_points_p_q_list = ((1, 0), (1, 1), (2, 1), (1, 4), (5, 3))
        ei_tolerance = 10.0 * numpy.finfo(numpy.float64).eps
        grad_ei_tolerance = 1.0e-13
        numpy.random.seed(78532)

        for test_case in self.gp_test_environments:
            domain, gaussian_process = test_case

            for num_to_sample, num_being_sampled in num_points_p_q_list:
                points_to_sample = domain.generate_uniform_random_points_in_domain(num_to_sample)
                points_being_sampled = domain.generate_uniform_random_points_in_domain(num_being_sampled)

                union_of_points = numpy.reshape(numpy.append(points_to_sample, points_being_sampled), (num_to_sample + num_being_sampled, self.dim))
                ei_eval = ExpectedImprovement(
                    gaussian_process,
                    points_to_sample,
                    points_being_sampled=points_being_sampled,
                    num_mc_iterations=self.num_mc_iterations,
                )

                # Compute quantities required for EI
                mu_star = ei_eval._gaussian_process.compute_mean_of_points(union_of_points)
                var_star = ei_eval._gaussian_process.compute_variance_of_points(union_of_points)

                # Check EI
                # Save state first to restore at the end (o/w other "random" events will get screwed up)
                rng_state = numpy.random.get_state()
                numpy.random.seed(self.rng_seed)
                ei_vectorized = ei_eval._compute_expected_improvement_monte_carlo(mu_star, var_star)
                numpy.random.seed(self.rng_seed)
                ei_naive = ei_eval._compute_expected_improvement_monte_carlo_naive(mu_star, var_star)
                self.assert_scalar_within_relative(ei_vectorized, ei_naive, ei_tolerance)

                # Compute quantities required for grad EI
                grad_mu = ei_eval._gaussian_process.compute_grad_mean_of_points(
                    union_of_points,
                    num_derivatives=num_to_sample,
                )
                grad_chol_decomp = ei_eval._gaussian_process.compute_grad_cholesky_variance_of_points(
                    union_of_points,
                    num_derivatives=num_to_sample,
                )

                # Check grad EI
                numpy.random.seed(self.rng_seed)
                grad_ei_vectorized = ei_eval._compute_grad_expected_improvement_monte_carlo(
                    mu_star,
                    var_star,
                    grad_mu,
                    grad_chol_decomp,
                )
                numpy.random.seed(self.rng_seed)
                grad_ei_naive = ei_eval._compute_grad_expected_improvement_monte_carlo_naive(
                    mu_star,
                    var_star,
                    grad_mu,
                    grad_chol_decomp,
                )
                self.assert_vector_within_relative(grad_ei_vectorized, grad_ei_naive, grad_ei_tolerance)

                # Restore state
                numpy.random.set_state(rng_state)
Beispiel #12
0
# data containers for pickle storage
list_best = []
list_cost = []
list_sampled_IS = []
list_sampled_points = []
list_sampled_vals = []
list_noise_var = []
list_raw_voi = []
best_sampled_val = np.amin(problem.hist_data._points_sampled_value)
truth_at_init_best_sampled = problem.obj_func_min.evaluate(
    problem.truth_is, problem.hist_data.points_sampled[
        np.argmin(problem.hist_data._points_sampled_value), :])
truth_at_best_sampled = truth_at_init_best_sampled
total_cost = 0.0
for ego_n in range(problem.num_iterations):
    expected_improvement_evaluator = ExpectedImprovement(ego_gp)
    min_negative_ei = np.inf

    def negative_ego_func(x):
        expected_improvement_evaluator.set_current_point(x.reshape((1, -1)))
        return -1.0 * expected_improvement_evaluator.compute_expected_improvement(
        )

    def negative_ego_grad_func(x):
        expected_improvement_evaluator.set_current_point(x.reshape((1, -1)))
        return -1.0 * expected_improvement_evaluator.compute_grad_expected_improvement(
        )[0, :]

    def min_negative_ego_func(start_point):
        return bfgs_optimization_grad(start_point, negative_ego_func,
                                      negative_ego_grad_func,
    def compute_next_points_to_sample_response(self, params, optimizer_method_name, route_name, *args, **kwargs):
        """Compute the next points to sample (and their expected improvement) using optimizer_method_name from params in the request.

        .. Warning:: Attempting to find ``num_to_sample`` optimal points with
          ``num_sampled < num_to_sample`` historical points sampled can cause matrix issues under
          some conditions. Try requesting ``num_to_sample < num_sampled`` points for better
          performance. To bootstrap more points try sampling at random, or from a grid.

        :param request_params: the deserialized REST request, containing ei_optimizer_parameters and gp_historical_info
        :type request_params: a deserialized self.request_schema object as a dict
        :param optimizer_method_name: the optimization method to use
        :type optimizer_method_name: string in :const:`moe.views.constant.NEXT_POINTS_OPTIMIZER_METHOD_NAMES`
        :param route_name: name of the route being called
        :type route_name: string in :const:`moe.views.constant.ALL_REST_ROUTES_ROUTE_NAME_TO_ENDPOINT`
        :param ``*args``: extra args to be passed to optimization method
        :param ``**kwargs``: extra kwargs to be passed to optimization method

        """
        points_being_sampled = numpy.array(params.get('points_being_sampled'))
        num_to_sample = params.get('num_to_sample')
        num_mc_iterations = params.get('mc_iterations')
        max_num_threads = params.get('max_num_threads')

        gaussian_process = _make_gp_from_params(params)

        ei_opt_status = {}
        # TODO(GH-89): Make the optimal_learning library handle this case 'organically' with
        # reasonable default behavior and remove hacks like this one.
        if gaussian_process.num_sampled == 0:
            # If there is no initial data we bootstrap with random points
            py_domain = _make_domain_from_params(params, python_version=True)
            next_points = py_domain.generate_uniform_random_points_in_domain(num_to_sample)
            ei_opt_status['found_update'] = True
            expected_improvement_evaluator = PythonExpectedImprovement(
                    gaussian_process,
                    points_being_sampled=points_being_sampled,
                    num_mc_iterations=num_mc_iterations,
                    )
        else:
            # Calculate the next best points to sample given the historical data

            optimizer_class, optimizer_parameters, num_random_samples = _make_optimizer_parameters_from_params(params)

            if optimizer_class == python_optimization.LBFGSBOptimizer:
                domain = RepeatedDomain(num_to_sample, _make_domain_from_params(params, python_version=True))
                expected_improvement_evaluator = PythonExpectedImprovement(
                        gaussian_process,
                        points_being_sampled=points_being_sampled,
                        num_mc_iterations=num_mc_iterations,
                        mvndst_parameters=_make_mvndst_parameters_from_params(params)
                        )

                opt_method = getattr(moe.optimal_learning.python.python_version.expected_improvement, optimizer_method_name)
            else:
                domain = _make_domain_from_params(params, python_version=False)
                expected_improvement_evaluator = ExpectedImprovement(
                        gaussian_process,
                        points_being_sampled=points_being_sampled,
                        num_mc_iterations=num_mc_iterations,
                        )

                opt_method = getattr(moe.optimal_learning.python.cpp_wrappers.expected_improvement, optimizer_method_name)

            expected_improvement_optimizer = optimizer_class(
                    domain,
                    expected_improvement_evaluator,
                    optimizer_parameters,
                    num_random_samples=num_random_samples,
                    )

            with timing_context(EPI_OPTIMIZATION_TIMING_LABEL):
                next_points = opt_method(
                    expected_improvement_optimizer,
                    params.get('optimizer_info')['num_multistarts'],  # optimizer_parameters.num_multistarts,
                    num_to_sample,
                    max_num_threads=max_num_threads,
                    status=ei_opt_status,
                    *args,
                    **kwargs
                )

        # TODO(GH-285): Use analytic q-EI here
        # TODO(GH-314): Need to resolve poential issue with NaNs before using q-EI here
        # It may be sufficient to check found_update == False in ei_opt_status
        # and then use q-EI, else set EI = 0.
        expected_improvement_evaluator.current_point = next_points
        # The C++ may fail to compute EI with some ``next_points`` inputs (e.g.,
        # ``points_to_sample`` and ``points_begin_sampled`` are too close
        # together or too close to ``points_sampled``). We catch the exception when this happens
        # and attempt a more numerically robust option.
        try:
            expected_improvement = expected_improvement_evaluator.compute_expected_improvement()
        except Exception as exception:
            self.log.info('EI computation failed, probably b/c GP-variance matrix is singular. Error: {0:s}'.format(exception))

            # ``_compute_expected_improvement_monte_carlo`` in
            # :class:`moe.optimal_learning.python.python_version.expected_improvement.ExpectedImprovement`
            # has a more reliable (but very expensive) way to deal with singular variance matrices.
            python_ei_eval = PythonExpectedImprovement(
                expected_improvement_evaluator._gaussian_process,
                points_to_sample=next_points,
                points_being_sampled=points_being_sampled,
                num_mc_iterations=num_mc_iterations,
            )
            expected_improvement = python_ei_eval.compute_expected_improvement(force_monte_carlo=True)

        return self.form_response({
                'endpoint': route_name,
                'points_to_sample': next_points.tolist(),
                'status': {
                    'expected_improvement': expected_improvement,
                    'optimizer_success': ei_opt_status,
                    },
                })
    def compute_next_points_to_sample_response(self, params,
                                               optimizer_method_name,
                                               route_name, *args, **kwargs):
        """Compute the next points to sample (and their expected improvement) using optimizer_method_name from params in the request.

        .. Warning:: Attempting to find ``num_to_sample`` optimal points with
          ``num_sampled < num_to_sample`` historical points sampled can cause matrix issues under
          some conditions. Try requesting ``num_to_sample < num_sampled`` points for better
          performance. To bootstrap more points try sampling at random, or from a grid.

        :param request_params: the deserialized REST request, containing ei_optimizer_parameters and gp_historical_info
        :type request_params: a deserialized self.request_schema object as a dict
        :param optimizer_method_name: the optimization method to use
        :type optimizer_method_name: string in :const:`moe.views.constant.NEXT_POINTS_OPTIMIZER_METHOD_NAMES`
        :param route_name: name of the route being called
        :type route_name: string in :const:`moe.views.constant.ALL_REST_ROUTES_ROUTE_NAME_TO_ENDPOINT`
        :param ``*args``: extra args to be passed to optimization method
        :param ``**kwargs``: extra kwargs to be passed to optimization method

        """
        points_being_sampled = numpy.array(params.get('points_being_sampled'))
        num_to_sample = params.get('num_to_sample')
        num_mc_iterations = params.get('mc_iterations')
        max_num_threads = params.get('max_num_threads')

        gaussian_process = _make_gp_from_params(params)

        ei_opt_status = {}
        # TODO(GH-89): Make the optimal_learning library handle this case 'organically' with
        # reasonable default behavior and remove hacks like this one.
        if gaussian_process.num_sampled == 0:
            # If there is no initial data we bootstrap with random points
            py_domain = _make_domain_from_params(params, python_version=True)
            next_points = py_domain.generate_uniform_random_points_in_domain(
                num_to_sample)
            ei_opt_status['found_update'] = True
            expected_improvement_evaluator = PythonExpectedImprovement(
                gaussian_process,
                points_being_sampled=points_being_sampled,
                num_mc_iterations=num_mc_iterations,
            )
        else:
            # Calculate the next best points to sample given the historical data

            optimizer_class, optimizer_parameters, num_random_samples = _make_optimizer_parameters_from_params(
                params)

            if optimizer_class == python_optimization.LBFGSBOptimizer:
                domain = RepeatedDomain(
                    num_to_sample,
                    _make_domain_from_params(params, python_version=True))
                expected_improvement_evaluator = PythonExpectedImprovement(
                    gaussian_process,
                    points_being_sampled=points_being_sampled,
                    num_mc_iterations=num_mc_iterations,
                    mvndst_parameters=_make_mvndst_parameters_from_params(
                        params))

                opt_method = getattr(
                    moe.optimal_learning.python.python_version.
                    expected_improvement, optimizer_method_name)
            else:
                domain = _make_domain_from_params(params, python_version=False)
                expected_improvement_evaluator = ExpectedImprovement(
                    gaussian_process,
                    points_being_sampled=points_being_sampled,
                    num_mc_iterations=num_mc_iterations,
                )

                opt_method = getattr(
                    moe.optimal_learning.python.cpp_wrappers.
                    expected_improvement, optimizer_method_name)

            expected_improvement_optimizer = optimizer_class(
                domain,
                expected_improvement_evaluator,
                optimizer_parameters,
                num_random_samples=num_random_samples,
            )

            with timing_context(EPI_OPTIMIZATION_TIMING_LABEL):
                next_points = opt_method(
                    expected_improvement_optimizer,
                    params.get('optimizer_info')
                    ['num_multistarts'],  # optimizer_parameters.num_multistarts,
                    num_to_sample,
                    max_num_threads=max_num_threads,
                    status=ei_opt_status,
                    *args,
                    **kwargs)

        # TODO(GH-285): Use analytic q-EI here
        # TODO(GH-314): Need to resolve poential issue with NaNs before using q-EI here
        # It may be sufficient to check found_update == False in ei_opt_status
        # and then use q-EI, else set EI = 0.
        expected_improvement_evaluator.current_point = next_points
        # The C++ may fail to compute EI with some ``next_points`` inputs (e.g.,
        # ``points_to_sample`` and ``points_begin_sampled`` are too close
        # together or too close to ``points_sampled``). We catch the exception when this happens
        # and attempt a more numerically robust option.
        try:
            expected_improvement = expected_improvement_evaluator.compute_expected_improvement(
            )
        except Exception as exception:
            self.log.info(
                'EI computation failed, probably b/c GP-variance matrix is singular. Error: {0:s}'
                .format(exception))

            # ``_compute_expected_improvement_monte_carlo`` in
            # :class:`moe.optimal_learning.python.python_version.expected_improvement.ExpectedImprovement`
            # has a more reliable (but very expensive) way to deal with singular variance matrices.
            python_ei_eval = PythonExpectedImprovement(
                expected_improvement_evaluator._gaussian_process,
                points_to_sample=next_points,
                points_being_sampled=points_being_sampled,
                num_mc_iterations=num_mc_iterations,
            )
            expected_improvement = python_ei_eval.compute_expected_improvement(
                force_monte_carlo=True)

        return self.form_response({
            'endpoint': route_name,
            'points_to_sample': next_points.tolist(),
            'status': {
                'expected_improvement': expected_improvement,
                'optimizer_success': ei_opt_status,
            },
        })