Exemplo n.º 1
0
    def test_evaluate_log_likelihood_at_points(self):
        """Check that ``evaluate_log_likelihood_at_hyperparameter_list`` computes and orders results correctly."""
        num_sampled = 5

        self.gp_test_environment_input.num_sampled = num_sampled
        _, gaussian_process = self._build_gaussian_process_test_data(
            self.gp_test_environment_input)
        python_cov, historical_data = gaussian_process.get_core_data_copy()

        lml = GaussianProcessLogMarginalLikelihood(python_cov, historical_data)

        num_to_eval = 10
        domain_bounds = [
            self.gp_test_environment_input.hyperparameter_interval
        ] * self.gp_test_environment_input.num_hyperparameters
        domain = TensorProductDomain(domain_bounds)
        hyperparameters_to_evaluate = domain.generate_uniform_random_points_in_domain(
            num_to_eval)

        test_values = evaluate_log_likelihood_at_hyperparameter_list(
            lml, hyperparameters_to_evaluate)

        for i, value in enumerate(test_values):
            lml.hyperparameters = hyperparameters_to_evaluate[i, ...]
            truth = lml.compute_log_likelihood()
            assert value == truth
Exemplo n.º 2
0
    def test_hyperparameter_gradient_pings(self):
        """Ping test (compare analytic result to finite difference) the gradient wrt hyperparameters."""
        h = 2.0e-3
        tolerance = 4.0e-5
        num_tests = 10

        dim = 3
        num_hyperparameters = dim + 1
        hyperparameter_interval = ClosedInterval(3.0, 5.0)

        domain = TensorProductDomain(
            ClosedInterval.build_closed_intervals_from_list([[-1.0, 1.0],
                                                             [-1.0, 1.0],
                                                             [-1.0, 1.0]]))

        points1 = domain.generate_uniform_random_points_in_domain(num_tests)
        points2 = domain.generate_uniform_random_points_in_domain(num_tests)

        for i in xrange(num_tests):
            point_one = points1[i, ...]
            point_two = points2[i, ...]

            covariance = gp_utils.fill_random_covariance_hyperparameters(
                hyperparameter_interval,
                num_hyperparameters,
                covariance_type=self.CovarianceClass,
            )

            analytic_grad = covariance.hyperparameter_grad_covariance(
                point_one, point_two)
            for k in xrange(covariance.num_hyperparameters):
                hyperparameters_old = covariance.hyperparameters

                # hyperparamter + h
                hyperparameters_p = numpy.copy(hyperparameters_old)
                hyperparameters_p[k] += h
                covariance.hyperparameters = hyperparameters_p
                cov_p = covariance.covariance(point_one, point_two)
                covariance.hyperparameters = hyperparameters_old

                # hyperparamter - h
                hyperparameters_m = numpy.copy(hyperparameters_old)
                hyperparameters_m[k] -= h
                covariance.hyperparameters = hyperparameters_m
                cov_m = covariance.covariance(point_one, point_two)
                covariance.hyperparameters = hyperparameters_old

                # calculate finite diff
                fd_grad = (cov_p - cov_m) / (2.0 * h)

                self.assert_scalar_within_relative(fd_grad, analytic_grad[k],
                                                   tolerance)
Exemplo n.º 3
0
class NullOptimizerTest(OptimalLearningTestCase):
    """Test the NullOptimizer on a simple objective.

    NullOptimizer should do nothing.
    Multistarting it should be the same as a 'dumb' search over points.

    """
    @T.class_setup
    def base_setup(self):
        """Set up a test case for optimizing a simple quadratic polynomial."""
        self.dim = 3
        domain_bounds = [ClosedInterval(-1.0, 1.0)] * self.dim
        self.domain = TensorProductDomain(domain_bounds)

        maxima_point = numpy.full(self.dim, 0.5)
        current_point = numpy.zeros(self.dim)
        self.polynomial = QuadraticFunction(maxima_point, current_point)
        self.null_optimizer = NullOptimizer(self.domain, self.polynomial)

    def test_null_optimizer(self):
        """Test that null optimizer does not change current_point."""
        current_point_old = self.null_optimizer.objective_function.current_point
        self.null_optimizer.optimize()
        current_point_new = self.null_optimizer.objective_function.current_point
        self.assert_vector_within_relative(current_point_old,
                                           current_point_new, 0.0)

    def test_multistarted_null_optimizer(self):
        """Test that multistarting null optimizer just evalutes the function and indentifies the max."""
        num_points = 15
        points = self.domain.generate_uniform_random_points_in_domain(
            num_points)

        truth = numpy.empty(num_points)
        for i, point in enumerate(points):
            self.null_optimizer.objective_function.current_point = point
            truth[
                i] = self.null_optimizer.objective_function.compute_objective_function(
                )

        best_index = numpy.argmax(truth)
        truth_best_point = points[best_index, ...]

        test_best_point, test_values = multistart_optimize(
            self.null_optimizer, starting_points=points)

        self.assert_vector_within_relative(test_best_point, truth_best_point,
                                           0.0)
        self.assert_vector_within_relative(test_values, truth, 0.0)
Exemplo n.º 4
0
    def test_hyperparameter_gradient_pings(self):
        """Ping test (compare analytic result to finite difference) the gradient wrt hyperparameters."""
        h = 2.0e-3
        tolerance = 4.0e-5
        num_tests = 10

        dim = 3
        num_hyperparameters = dim + 1
        hyperparameter_interval = ClosedInterval(3.0, 5.0)

        domain = TensorProductDomain(ClosedInterval.build_closed_intervals_from_list([[-1.0, 1.0], [-1.0, 1.0], [-1.0, 1.0]]))

        points1 = domain.generate_uniform_random_points_in_domain(num_tests)
        points2 = domain.generate_uniform_random_points_in_domain(num_tests)

        for i in xrange(num_tests):
            point_one = points1[i, ...]
            point_two = points2[i, ...]

            covariance = gp_utils.fill_random_covariance_hyperparameters(
                hyperparameter_interval,
                num_hyperparameters,
                covariance_type=self.CovarianceClass,
            )

            analytic_grad = covariance.hyperparameter_grad_covariance(point_one, point_two)
            for k in xrange(covariance.num_hyperparameters):
                hyperparameters_old = covariance.hyperparameters

                # hyperparamter + h
                hyperparameters_p = numpy.copy(hyperparameters_old)
                hyperparameters_p[k] += h
                covariance.hyperparameters = hyperparameters_p
                cov_p = covariance.covariance(point_one, point_two)
                covariance.hyperparameters = hyperparameters_old

                # hyperparamter - h
                hyperparameters_m = numpy.copy(hyperparameters_old)
                hyperparameters_m[k] -= h
                covariance.hyperparameters = hyperparameters_m
                cov_m = covariance.covariance(point_one, point_two)
                covariance.hyperparameters = hyperparameters_old

                # calculate finite diff
                fd_grad = (cov_p - cov_m) / (2.0 * h)

                self.assert_scalar_within_relative(fd_grad, analytic_grad[k], tolerance)
Exemplo n.º 5
0
class NullOptimizerTest(OptimalLearningTestCase):

    """Test the NullOptimizer on a simple objective.

    NullOptimizer should do nothing.
    Multistarting it should be the same as a 'dumb' search over points.

    """

    @T.class_setup
    def base_setup(self):
        """Set up a test case for optimizing a simple quadratic polynomial."""
        self.dim = 3
        domain_bounds = [ClosedInterval(-1.0, 1.0)] * self.dim
        self.domain = TensorProductDomain(domain_bounds)

        maxima_point = numpy.full(self.dim, 0.5)
        current_point = numpy.zeros(self.dim)
        self.polynomial = QuadraticFunction(maxima_point, current_point)
        self.null_optimizer = NullOptimizer(self.domain, self.polynomial)

    def test_null_optimizer(self):
        """Test that null optimizer does not change current_point."""
        current_point_old = self.null_optimizer.objective_function.current_point
        self.null_optimizer.optimize()
        current_point_new = self.null_optimizer.objective_function.current_point
        self.assert_vector_within_relative(current_point_old, current_point_new, 0.0)

    def test_multistarted_null_optimizer(self):
        """Test that multistarting null optimizer just evalutes the function and indentifies the max."""
        num_points = 15
        points = self.domain.generate_uniform_random_points_in_domain(num_points)

        truth = numpy.empty(num_points)
        for i, point in enumerate(points):
            self.null_optimizer.objective_function.current_point = point
            truth[i] = self.null_optimizer.objective_function.compute_objective_function()

        best_index = numpy.argmax(truth)
        truth_best_point = points[best_index, ...]

        test_best_point, test_values = multistart_optimize(self.null_optimizer, starting_points=points)

        self.assert_vector_within_relative(test_best_point, truth_best_point, 0.0)
        self.assert_vector_within_relative(test_values, truth, 0.0)
Exemplo n.º 6
0
    def test_evaluate_log_likelihood_at_points(self):
        """Check that ``evaluate_log_likelihood_at_hyperparameter_list`` computes and orders results correctly."""
        num_sampled = 5

        self.gp_test_environment_input.num_sampled = num_sampled
        _, gaussian_process = self._build_gaussian_process_test_data(self.gp_test_environment_input)
        python_cov, historical_data = gaussian_process.get_core_data_copy()

        lml = GaussianProcessLogMarginalLikelihood(python_cov, historical_data)

        num_to_eval = 10
        domain_bounds = [self.gp_test_environment_input.hyperparameter_interval] * self.gp_test_environment_input.num_hyperparameters
        domain = TensorProductDomain(domain_bounds)
        hyperparameters_to_evaluate = domain.generate_uniform_random_points_in_domain(num_to_eval)

        test_values = evaluate_log_likelihood_at_hyperparameter_list(lml, hyperparameters_to_evaluate)

        for i, value in enumerate(test_values):
            lml.hyperparameters = hyperparameters_to_evaluate[i, ...]
            truth = lml.compute_log_likelihood()
            assert value == truth
Exemplo n.º 7
0
class GradientDescentOptimizerTest(OptimalLearningTestCase):

    r"""Test Gradient Descent on a simple quadratic objective.

    We check GD in an unconstrained setting, a constrained setting, and we test multistarting it.

    We don't test the stochastic averaging option meaningfully. We check that the optimizer will average
    the number of steps specified by input. We also check that the simple unconstrained case can also be solved
    with averaging on\*.

    \* This is not much of a test. The problem is convex and isotropic so GD will take a more or less straight
    path to the maxima. Averaging can only reduce the accuracy of the solve.

    TODO(GH-179): Build a simple stochastic objective and test the stochastic component fully.

    """

    @T.class_setup
    def base_setup(self):
        """Set up a test case for optimizing a simple quadratic polynomial."""
        self.dim = 3
        domain_bounds = [ClosedInterval(-1.0, 1.0)] * self.dim
        self.domain = TensorProductDomain(domain_bounds)

        maxima_point = numpy.full(self.dim, 0.5)
        current_point = numpy.zeros(self.dim)
        self.polynomial = QuadraticFunction(maxima_point, current_point)

        max_num_steps = 250
        max_num_restarts = 10
        num_steps_averaged = 0
        gamma = 0.7  # smaller gamma would lead to faster convergence, but we don't want to make the problem too easy
        pre_mult = 1.0
        max_relative_change = 0.8
        tolerance = 1.0e-12
        self.gd_parameters = GradientDescentParameters(
            max_num_steps,
            max_num_restarts,
            num_steps_averaged,
            gamma,
            pre_mult,
            max_relative_change,
            tolerance,
        )

        approx_grad = False
        max_func_evals = 150000
        max_metric_correc = 10
        factr = 1000.0
        pgtol = 1e-10
        epsilon = 1e-8
        self.BFGS_parameters = LBFGSBParameters(
            approx_grad,
            max_func_evals,
            max_metric_correc,
            factr,
            pgtol,
            epsilon,
        )

    def test_gradient_descent_optimizer(self):
        """Check that gradient descent can find the optimum of the quadratic test objective."""
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), 0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        gradient_descent_optimizer = GradientDescentOptimizer(self.domain, self.polynomial, self.gd_parameters)
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value, self.polynomial.optimum_value, tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), tolerance)

    def test_get_averaging_range(self):
        """Test the method used to produce what interval to average over in Polyak-Ruppert averaging."""
        num_steps_total = 250
        end = num_steps_total + 1
        num_steps_averaged_input_list = [-1, 0, 1, 20, 100, 249, 250, 251, 10000]
        truth_list = [(1, end), (250, end), (250, end), (231, end), (151, end), (2, end), (1, end), (1, end), (1, end)]

        for i, truth in enumerate(truth_list):
            start, end = GradientDescentOptimizer._get_averaging_range(num_steps_averaged_input_list[i], num_steps_total)
            T.assert_equal(start, truth[0])
            T.assert_equal(end, truth[1])

    def test_gradient_descent_optimizer_with_averaging(self):
        """Check that gradient descent can find the optimum of the quadratic test objective with averaging on.

        This test doesn't exercise the purpose of averaging (i.e., this objective isn't stochastic), but it does
        check that it at least runs.

        """
        num_steps_averaged = self.gd_parameters.max_num_steps * 3 / 4
        gd_parameters_averaging = GradientDescentParameters(
            self.gd_parameters.max_num_steps,
            self.gd_parameters.max_num_restarts,
            num_steps_averaged,
            self.gd_parameters.gamma,
            self.gd_parameters.pre_mult,
            self.gd_parameters.max_relative_change,
            self.gd_parameters.tolerance,
        )
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), 0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        gradient_descent_optimizer = GradientDescentOptimizer(self.domain, self.polynomial, gd_parameters_averaging)
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-10
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value, self.polynomial.optimum_value, tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), tolerance)

    def test_gradient_descent_optimizer_constrained(self):
        """Check that gradient descent can find the global optimum (in a domain) when the true optimum is outside."""
        # Domain where the optimum, (0.5, 0.5, 0.5), lies outside the domain
        domain_bounds = [ClosedInterval(0.05, 0.32), ClosedInterval(0.05, 0.6), ClosedInterval(0.05, 0.32)]
        domain = TensorProductDomain(domain_bounds)
        gradient_descent_optimizer = GradientDescentOptimizer(domain, self.polynomial, self.gd_parameters)

        # Work out what the maxima point woudl be given the domain constraints (i.e., project to the nearest point on domain)
        constrained_optimum_point = self.polynomial.optimum_point
        for i, bounds in enumerate(domain_bounds):
            if constrained_optimum_point[i] > bounds.max:
                constrained_optimum_point[i] = bounds.max
            elif constrained_optimum_point[i] < bounds.min:
                constrained_optimum_point[i] = bounds.min

        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        initial_value = gradient_descent_optimizer.objective_function.compute_objective_function()
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, constrained_optimum_point, tolerance)

        # Verify optimized value is better than initial guess
        final_value = self.polynomial.compute_objective_function()
        T.assert_gt(final_value, initial_value)

        # Verify derivative: only get 0 derivative if the coordinate lies inside domain boundaries
        gradient = self.polynomial.compute_grad_objective_function()
        for i, bounds in enumerate(domain_bounds):
            if bounds.is_inside(self.polynomial.optimum_point[i]):
                self.assert_scalar_within_relative(gradient[i], 0.0, tolerance)

    def test_multistarted_gradient_descent_optimizer_crippled_start(self):
        """Check that multistarted GD is finding the best result from GD."""
        # Only allow 1 GD iteration.
        gd_parameters_crippled = GradientDescentParameters(
            1,
            1,
            self.gd_parameters.num_steps_averaged,
            self.gd_parameters.gamma,
            self.gd_parameters.pre_mult,
            self.gd_parameters.max_relative_change,
            self.gd_parameters.tolerance,
        )
        gradient_descent_optimizer_crippled = GradientDescentOptimizer(self.domain, self.polynomial, gd_parameters_crippled)

        num_points = 15
        points = self.domain.generate_uniform_random_points_in_domain(num_points)

        multistart_optimizer = MultistartOptimizer(gradient_descent_optimizer_crippled, num_points)
        test_best_point, _ = multistart_optimizer.optimize(random_starts=points)
        # This point set won't include the optimum so multistart GD won't find it.
        for value in (test_best_point - self.polynomial.optimum_point):
            T.assert_not_equal(value, 0.0)

        points_with_opt = numpy.append(points, self.polynomial.optimum_point.reshape((1, self.polynomial.dim)), axis=0)
        test_best_point, _ = multistart_optimizer.optimize(random_starts=points_with_opt)
        # This point set will include the optimum so multistart GD will find it.
        for value in (test_best_point - self.polynomial.optimum_point):
            T.assert_equal(value, 0.0)

    def test_multistarted_gradient_descent_optimizer(self):
        """Check that multistarted GD can find the optimum in a 'very' large domain."""
        # Set a large domain: a single GD run is unlikely to reach the optimum
        domain_bounds = [ClosedInterval(-10.0, 10.0)] * self.dim
        domain = TensorProductDomain(domain_bounds)

        tolerance = 2.0e-10
        num_points = 10
        gradient_descent_optimizer = GradientDescentOptimizer(domain, self.polynomial, self.gd_parameters)
        multistart_optimizer = MultistartOptimizer(gradient_descent_optimizer, num_points)

        output, _ = multistart_optimizer.optimize()
        # Verify coordinates
        self.assert_vector_within_relative(output, self.polynomial.optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value, self.polynomial.optimum_value, tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), tolerance)

    def test_bfgs_optimizer(self):
        """Check that BFGS can find the optimum of the quadratic test objective."""
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), 0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        bfgs_optimizer = LBFGSBOptimizer(self.domain, self.polynomial, self.BFGS_parameters)
        bfgs_optimizer.optimize()
        output = bfgs_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        bfgs_optimizer.objective_function.current_point = initial_guess
        bfgs_optimizer.optimize()
        output = bfgs_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value, self.polynomial.optimum_value, tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), tolerance)

    def test_multistarted_bfgs_optimizer(self):
        """Check that multistarted GD can find the optimum in a 'very' large domain."""
        # Set a large domain: a single GD run is unlikely to reach the optimum
        domain_bounds = [ClosedInterval(-10.0, 10.0)] * self.dim
        domain = TensorProductDomain(domain_bounds)

        tolerance = 2.0e-10
        num_points = 10
        bfgs_optimizer = LBFGSBOptimizer(domain, self.polynomial, self.BFGS_parameters)
        multistart_optimizer = MultistartOptimizer(bfgs_optimizer, num_points)

        output, _ = multistart_optimizer.optimize()
        # Verify coordinates
        self.assert_vector_within_relative(output, self.polynomial.optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value, self.polynomial.optimum_value, tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient, numpy.zeros(self.polynomial.dim), tolerance)
Exemplo n.º 8
0
def main():

    args = docopt(__doc__)

    # Parse arguments
    mesh = args['<mesh>']
    weights = np.load(args['<weightfile>'])
    init_centroid = np.genfromtxt(args['<init_centroid>'])
    coil = args['<coil>']
    output_file = args['<output_file>']
    cpus = int(args['--cpus']) or 8
    tmpdir = args['--tmp-dir'] or os.getenv('TMPDIR') or "/tmp/"
    num_iters = int(args['--n-iters']) or 50
    min_samps = int(args['--min-var-samps']) or 10
    tol = float(args['--convergence']) or 0.001
    history = args['--history']
    skip_convergence = args['--skip-convergence']
    options = args['--options']

    if options:
        with open(options, 'r') as f:
            opts = json.load(f)
        logging.info("Using custom options file {}".format(options))
        logging.info("{}".format('\''.join(
            [f"{k}:{v}" for k, v in opts.items()])))
    else:
        opts = {}

    logging.info('Using {} cpus'.format(cpus))

    f = FieldFunc(mesh_file=mesh,
                  initial_centroid=init_centroid,
                  tet_weights=weights,
                  coil=coil,
                  field_dir=tmpdir,
                  cpus=cpus,
                  **opts)

    # Make search domain
    search_domain = TensorProductDomain([
        ClosedInterval(f.bounds[0, 0], f.bounds[0, 1]),
        ClosedInterval(f.bounds[1, 0], f.bounds[1, 1]),
        ClosedInterval(0, 180)
    ])

    c_search_domain = cTensorProductDomain([
        ClosedInterval(f.bounds[0, 0], f.bounds[0, 1]),
        ClosedInterval(f.bounds[1, 0], f.bounds[1, 1]),
        ClosedInterval(0, 180)
    ])

    # Generate historical points
    prior = DefaultPrior(n_dims=3 + 2, num_noise=1)
    prior.tophat = TophatPrior(-2, 5)
    prior.ln_prior = NormalPrior(12.5, 1.6)
    hist_pts = cpus
    i = 0
    init_pts = search_domain.generate_uniform_random_points_in_domain(hist_pts)
    observations = -f.evaluate(init_pts)
    hist_data = HistoricalData(dim=3, num_derivatives=0)
    hist_data.append_sample_points(
        [SamplePoint(inp, o, 0.0) for o, inp in zip(observations, init_pts)])

    # Train GP model
    gp_ll = GaussianProcessLogLikelihoodMCMC(historical_data=hist_data,
                                             derivatives=[],
                                             prior=prior,
                                             chain_length=1000,
                                             burnin_steps=2000,
                                             n_hypers=2**4,
                                             noisy=False)
    gp_ll.train()

    # Initialize grad desc params
    sgd_params = cGDParams(num_multistarts=200,
                           max_num_steps=50,
                           max_num_restarts=5,
                           num_steps_averaged=4,
                           gamma=0.7,
                           pre_mult=1.0,
                           max_relative_change=0.5,
                           tolerance=1.0e-10)

    num_samples = int(cpus * 1.3)
    best_point_history = []

    # Sum of errors buffer
    var_buffer = deque(maxlen=min_samps)
    for i in np.arange(0, num_iters):

        # Optimize qEI and pick samples
        points_to_sample, ei = gen_sample_from_qei(gp_ll.models[0],
                                                   c_search_domain,
                                                   sgd_params=sgd_params,
                                                   num_samples=num_samples,
                                                   num_mc=2**10)

        # Collect observations
        sampled_points = -f.evaluate(points_to_sample)
        evidence = [
            SamplePoint(c, v, 0.0)
            for c, v in zip(points_to_sample, sampled_points)
        ]

        # Update model
        gp_ll.add_sampled_points(evidence)
        gp_ll.train()

        # Pull model and pull values
        gp = gp_ll.models[0]
        min_point = np.argmin(gp._points_sampled_value)
        min_val = np.min(gp._points_sampled_value)
        best_coord = gp.get_historical_data_copy().points_sampled[min_point]

        logging.info('Iteration {} of {}'.format(i, num_iters))
        logging.info('Recommended Points:')
        logging.info(points_to_sample)
        logging.info('Expected Improvement: {}'.format(ei))
        logging.info('Current Best:')
        logging.info(f'f(x*)= {min_val}')
        logging.info(f'Coord: {best_coord}')
        best_point_history.append(str(min_val))

        if history:
            with open(history, 'w') as buf:
                buf.write('\n'.join(best_point_history))

        # Convergence check
        if (len(var_buffer) == var_buffer.maxlen) and not skip_convergence:
            deviation = sum([abs(x - min_val) for x in var_buffer])
            if deviation < tol:
                logging.info('Convergence reached!')
                logging.info('Deviation: {}'.format(deviation))
                logging.info('History length: {}'.format(var_buffer.maxlen))
                logging.info('Tolerance: {}'.format(tol))
                break

        var_buffer.append(min_val)

    # Save position and orientation matrix
    np.savetxt(output_file, best_coord)
Exemplo n.º 9
0
def multistart_hyperparameter_optimization(
    hyperparameter_optimizer,
    num_multistarts,
    randomness=None,
    max_num_threads=DEFAULT_MAX_NUM_THREADS,
    status=None,
):
    r"""Select the hyperparameters that maximize the specified log likelihood measure of model fit (over the historical data) within the specified domain.

    .. Note:: The following comments are copied from
      :func:`moe.optimal_learning.python.cpp_wrappers.log_likelihood.multistart_hyperparameter_optimization`.

    See :class:`moe.optimal_learning.python.python_version.log_likelihood.GaussianProcessLogMarginalLikelihood` and
    :class:`moe.optimal_learning.python.python_version.log_likelihood.GaussianProcessLeaveOneOutLogLikelihood`
    for an overview of some example log likelihood-like measures.

    Optimizers are: null ('dumb' search), gradient descent, newton
    Newton is the suggested optimizer, which is not presently available in Python (use the C++ interface). In Python,
    gradient descent is suggested.

    TODO(GH-57): Implement hessians and Newton's method.

    'dumb' search means this will just evaluate the objective log likelihood measure at num_multistarts 'points'
    (hyperparameters) in the domain, uniformly sampled using latin hypercube sampling.

    See gpp_python_common.cpp for C++ enum declarations laying out the options for objective and optimizer types.

    Currently, during optimization, we recommend that the coordinates of the initial guesses not differ from the
    coordinates of the optima by more than about 1 order of magnitude. This is a very (VERY!) rough guideline for
    sizing the domain and gd_parameters.num_multistarts; i.e., be wary of sets of initial guesses that cover the space too sparsely.

    Solution is guaranteed to lie within the region specified by "domain"; note that this may not be a
    true optima (i.e., the gradient may be substantially nonzero).

    .. WARNING:: this function fails if NO improvement can be found!  In that case,
       the output will always be the first randomly chosen point. status will report failure.

    TODO(GH-56): Allow callers to pass in a source of randomness.

    :param hyperparameter_optimizer: object that optimizes (e.g., gradient descent, newton) the desired log_likelihood
        measure over a domain (wrt the hyperparameters of covariance)
    :type hyperparameter_optimizer: interfaces.optimization_interfaces.OptimizerInterface subclass
    :param num_multistarts: number of times to multistart ``hyperparameter_optimizer``
    :type num_multistarts: int > 0
    :param randomness: random source used to generate multistart points (UNUSED)
    :type randomness: (UNUSED)
    :param max_num_threads: maximum number of threads to use, >= 1 (UNUSED)
    :type max_num_threads: int > 0
    :param status: (output) status messages (e.g., reporting on optimizer success, etc.)
    :type status: dict
    :return: hyperparameters that maximize the specified log likelihood measure within the specified domain
    :rtype: array of float64 with shape (log_likelihood_evaluator.num_hyperparameters)

    """
    # Producing the random starts in log10 space improves robustness by clustering some extra points near 0
    domain_bounds_log10 = numpy.log10(
        hyperparameter_optimizer.domain._domain_bounds)
    domain_log10 = TensorProductDomain(
        ClosedInterval.build_closed_intervals_from_list(domain_bounds_log10))
    random_starts = domain_log10.generate_uniform_random_points_in_domain(
        num_points=num_multistarts)
    random_starts = numpy.power(10.0, random_starts)

    best_hyperparameters, _ = multistart_optimize(
        hyperparameter_optimizer, starting_points=random_starts)

    # TODO(GH-59): Have GD actually indicate whether updates were found, e.g., in an IOContainer-like structure.
    found_flag = True
    if status is not None:
        status["gradient_descent_found_update"] = found_flag

    return best_hyperparameters
Exemplo n.º 10
0
        if IS != 0 and IS != 1:
            raise ValueError("IS has to be 0 or 1")
        elif IS == 0:
            val += numpy.random.normal()
        elif IS == 1:
            val += 2. * numpy.sin(10.0 * x[0] + 5.0 * x[1])
        return self._mult * val

    def noise_and_cost_func(self, IS, x):
        if IS != 0 and IS != 1:
            raise ValueError("IS has to be 0 or 1")
        return (1., 50) if IS == 0 else (1e-6, 1.)

    def getFuncName(self):
        return 'rbNew'


if __name__ == "__main__":
    rb_remi = RosenbrockRemi()
    python_search_domain = TensorProductDomain([
        ClosedInterval(bound[0], bound[1]) for bound in rb_remi._search_domain
    ])
    pts = python_search_domain.generate_uniform_random_points_in_domain(1000)
    print "rb remi"
    print "IS0: {0}".format(numpy.mean([rb_remi.evaluate(0, x) for x in pts]))
    print "IS1: {0}".format(numpy.mean([rb_remi.evaluate(1, x) for x in pts]))
    print "rb new"
    rb_new = RosenbrockNew()
    print "IS0: {0}".format(numpy.mean([rb_new.evaluate(0, x) for x in pts]))
    print "IS1: {0}".format(numpy.mean([rb_new.evaluate(1, x) for x in pts]))
Exemplo n.º 11
0
def multistart_hyperparameter_optimization(
        hyperparameter_optimizer,
        num_multistarts,
        randomness=None,
        max_num_threads=DEFAULT_MAX_NUM_THREADS,
        status=None,
):
    r"""Select the hyperparameters that maximize the specified log likelihood measure of model fit (over the historical data) within the specified domain.

    .. Note:: The following comments are copied from
      :func:`moe.optimal_learning.python.cpp_wrappers.log_likelihood.multistart_hyperparameter_optimization`.

    See :class:`moe.optimal_learning.python.python_version.log_likelihood.GaussianProcessLogMarginalLikelihood` and
    :class:`moe.optimal_learning.python.python_version.log_likelihood.GaussianProcessLeaveOneOutLogLikelihood`
    for an overview of some example log likelihood-like measures.

    Optimizers are: null ('dumb' search), gradient descent, newton
    Newton is the suggested optimizer, which is not presently available in Python (use the C++ interface). In Python,
    gradient descent is suggested.

    TODO(GH-57): Implement hessians and Newton's method.

    'dumb' search means this will just evaluate the objective log likelihood measure at num_multistarts 'points'
    (hyperparameters) in the domain, uniformly sampled using latin hypercube sampling.

    See gpp_python_common.cpp for C++ enum declarations laying out the options for objective and optimizer types.

    Currently, during optimization, we recommend that the coordinates of the initial guesses not differ from the
    coordinates of the optima by more than about 1 order of magnitude. This is a very (VERY!) rough guideline for
    sizing the domain and gd_parameters.num_multistarts; i.e., be wary of sets of initial guesses that cover the space too sparsely.

    Solution is guaranteed to lie within the region specified by "domain"; note that this may not be a
    true optima (i.e., the gradient may be substantially nonzero).

    .. WARNING:: this function fails if NO improvement can be found!  In that case,
       the output will always be the first randomly chosen point. status will report failure.

    TODO(GH-56): Allow callers to pass in a source of randomness.

    :param hyperparameter_optimizer: object that optimizes (e.g., gradient descent, newton) the desired log_likelihood
        measure over a domain (wrt the hyperparameters of covariance)
    :type hyperparameter_optimizer: interfaces.optimization_interfaces.OptimizerInterface subclass
    :param num_multistarts: number of times to multistart ``hyperparameter_optimizer``
    :type num_multistarts: int > 0
    :param randomness: random source used to generate multistart points (UNUSED)
    :type randomness: (UNUSED)
    :param max_num_threads: maximum number of threads to use, >= 1 (UNUSED)
    :type max_num_threads: int > 0
    :param status: status messages (e.g., reporting on optimizer success, etc.)
    :type status: dict
    :return: hyperparameters that maximize the specified log likelihood measure within the specified domain
    :rtype: array of float64 with shape (log_likelihood_evaluator.num_hyperparameters)

    """
    # Producing the random starts in log10 space improves robustness by clustering some extra points near 0
    domain_bounds_log10 = numpy.log10(hyperparameter_optimizer.domain._domain_bounds)
    domain_log10 = TensorProductDomain(ClosedInterval.build_closed_intervals_from_list(domain_bounds_log10))
    random_starts = domain_log10.generate_uniform_random_points_in_domain(num_points=num_multistarts)
    random_starts = numpy.power(10.0, random_starts)

    best_hyperparameters, _ = multistart_optimize(hyperparameter_optimizer, starting_points=random_starts)

    # TODO(GH-59): Have GD actually indicate whether updates were found, e.g., in an IOContainer-like structure.
    found_flag = True
    if status is not None:
        status["gradient_descent_found_update"] = found_flag

    return best_hyperparameters
Exemplo n.º 12
0
list_noise_var = []
list_raw_voi = []
init_best_idx = numpy.argmin(problem.hist_data._points_sampled_value[
    problem.hist_data._points_sampled[:, 0] == problem.truth_is])
best_sampled_val = problem.hist_data._points_sampled_value[init_best_idx]
truth_at_init_best_sampled = problem.obj_func_min.evaluate(
    problem.truth_is, problem.hist_data.points_sampled[init_best_idx, 1:])
truth_at_best_sampled = truth_at_init_best_sampled
total_cost = 0.
best_mu_star_truth = numpy.inf
for itr in range(problem.num_iterations):
    print "{0} , itr {1}".format(argv, itr)
    with Parallel(n_jobs=num_threads) as parallel:
        parallel_results = parallel(
            delayed(find_mu_star)(pt, pes_model.gp_model)
            for pt in unit_domain.generate_uniform_random_points_in_domain(
                num_multistart))
        mu_star, mu_star_point = process_parallel_results(parallel_results)
    mu_star_point_org_space = scale_back(mu_star_point, lower_bounds,
                                         upper_bounds)
    mu_star_truth = problem.obj_func_min.evaluate(problem.truth_is,
                                                  mu_star_point_org_space)
    best_mu_star_truth = min(best_mu_star_truth, mu_star_truth)
    pes_model.state = itr
    try:
        pt_to_sample, sample_is, acq, raw_acq = optimize_entropy(
            pes,
            pes_model,
            problem.obj_func_min.getDim(),
            num_discretization=1000,
            cost_func=cost_func,
            list_sample_is=problem.list_sample_is)
Exemplo n.º 13
0
def main():

    args = docopt(__doc__)

    #Parse arguments
    mesh        =   args['<mesh>']
    weights     =   np.load(args['<weightfile>'])
    C           =   np.load(args['<quad_const>'])
    b           =   np.load(args['<bounds>'])
    R           =   np.load(args['<affine>'])
    coil        =   args['<coil>']
    loc_out     =   args['<loc_out>']
    rot_out     =   args['<rot_out>']
    cpus        =   int(args['--cpus']) or 8
    tmpdir      =   args['--tmp-dir'] or os.getenv('TMPDIR') or "/tmp/"
    num_iters   =   args['--n-iters'] or 50


    #Make search domain
    search_domain = TensorProductDomain([
            ClosedInterval(b[0,0],b[0,1]), #X coord on quadratic surface
            ClosedInterval(b[1,0],b[1,1]), #Y coord on quadratic surface
            ClosedInterval(0,180) #Rotational angle
            ])

    c_search_domain = cTensorProductDomain([
            ClosedInterval(b[0,0],b[0,1]), 
            ClosedInterval(b[1,0],b[1,1]),
            ClosedInterval(0,180)
            ])

    #Make objective function
    f = FieldFunc(mesh_file=mesh, quad_surf_consts=C,
                  surf_to_mesh_matrix=R, tet_weights=weights,
                  field_dir=tmpdir, coil=coil, cpus=cpus)


    #Generate historical points
    hist_pts = int(cpus * 1.5)
    init_pts = search_domain.generate_uniform_random_points_in_domain(hist_pts)
    observations = -f.evaluate(init_pts)
    hist_data = HistoricalData(dim = 3, num_derivatives= 0)
    hist_data.append_sample_points([SamplePoint(inp,o,0.0) 
                                    for o,inp in 
                                    zip(observations,init_pts)])

    #Set up model specifications
    prior = DefaultPrior(n_dims = 3 + 2, num_noise=1)
    gp_ll = GaussianProcessLogLikelihoodMCMC(historical_data=hist_data,
                                             derivatives=[], prior=prior,
                                             chain_length=1000, burnin_steps=2000,
                                             n_hypers=2**4, noisy=False)
    gp_ll.train()

    #Initialize grad desc params
    sgd_params = cGDParams(num_multistarts=200, max_num_steps=50,
                           max_num_restarts=2, num_steps_averaged=4,
                           gamma=0.7, pre_mult=1.0, max_relative_change=0.5,
                           tolerance=1.0e-10)

    num_samples = int(cpus*1.3)
    best_point_history = []
    for i in np.arange(0,num_iters):
            
        #Optimize qEI and pick samples
        points_to_sample, ei = gen_sample_from_qei(gp_ll.models[0],
                                                   c_search_domain, sgd_params=sgd_params,
                                                   num_samples=num_samples, num_mc=2**10)

        #Collect observations
        sampled_points = -f.evaluate(points_to_sample)
        evidence = [SamplePoint(c,v,0.0) for c,v in zip(points_to_sample, sampled_points)]

        #Update model
        gp_ll.add_sampled_points(evidence)
        gp_ll.train()

        #Pull model and pull values
        gp = gp_ll.models[0]
        min_point = np.argmin(gp._points_sampled_value)
        min_val = np.min(gp._points_sampled_value)
        best_coord = gp.get_historical_data_copy().points_sampled[min_point]

        print('Recommended Points:')
        print(points_to_sample)
        print('Expected Improvement: {}'.format(ei))
        print('Current Best:')
        print('f(x*)=',min_val)
        print('Coord:', best_coord)

        best_point_history.append(min_val)

    #Once sampling is done take the best point and transform it back into native space
    preaff_loc = geolib.map_param_2_surf(best_coord[0],best_coord[1],C)
    preaff_rot,_ = geolib.map_rot_2_surf(best_coord[0],best_coord[1],best_coord[2],C)
    loc = np.matmul(R,preaff_loc)
    rot = np.matmul(R,preaff_rot)
    np.savetxt(loc_out,loc)
    np.savetxt(rot_out,rot)
Exemplo n.º 14
0
def plot_ato_cor(num_points, num_discretization):
    dim = 8
    num_func = 4
    num_repl = 100
    search_domain = TensorProductDomain(
        [ClosedInterval(0.0, 20.0) for i in range(dim)])
    average_points = search_domain.generate_uniform_random_points_in_domain(
        num_points)
    func_name_0_list = ["vanilla", "var2", "var3", "var4"]
    func_name_1_list = ["var3", "var4", "vanilla", "var2"]
    func_name_2_list = ["var4", "vanilla", "var2", "var3"]
    with open("{0}/mkg_ato.pickle".format(hyper_dir), 'rb') as f:
        data = pickle.load(f)
    hyper_param = data['hyperparam']
    kg_cov_cpp = cppMixedSquareExponential(hyperparameters=hyper_param)
    info_1 = 1
    info_2 = 2
    x_coords = np.linspace(0.0, 20.0, num=num_discretization)
    cor_IS = np.zeros(
        (num_func * num_repl * num_points, num_discretization, dim))
    cor_delta_gp = np.zeros(
        (num_func * num_repl * num_points, num_discretization, dim))
    count = 0
    for func_idx in range(num_func):
        for repl_no in range(num_repl):
            hist_data = construct_hist_data_from_pickle(
                dim=dim,
                directory=data_dir,
                IS_filename_dict={
                    0:
                    "kg_atoC_{0}_repl_{1}".format(func_name_0_list[func_idx],
                                                  repl_no),
                    1:
                    "kg_atoC_{0}_repl_{1}".format(func_name_1_list[func_idx],
                                                  repl_no),
                    2:
                    "kg_atoC_{0}_repl_{1}".format(func_name_2_list[func_idx],
                                                  repl_no)
                },
                combine_IS=True,
                sign=-1.0)
            kg_gp_cpp = GaussianProcessNew(kg_cov_cpp, hist_data, num_IS_in=2)
            for the_point in average_points:
                for which_dim in range(dim):
                    cor_IS[count, :,
                           which_dim] = compute_correlation_info_source(
                               the_point, info_1, info_2, which_dim, x_coords,
                               kg_gp_cpp)
                    cor_delta_gp[count, :,
                                 which_dim] = compute_correlation_delta_gp(
                                     the_point, info_1, info_2, which_dim,
                                     x_coords, kg_gp_cpp)
                count += 1
                print "ato, ct {0}".format(count)
    with open("{0}/ato_plot_data.pickle".format(plot_dir), "wb") as f:
        pickle.dump(
            {
                "cor_is": cor_IS,
                "cor_delta": cor_delta_gp,
                "x": x_coords
            }, f)
    plot_cor(x_coords, cor_IS, cor_delta_gp, dim, plot_dir, "ato")
Exemplo n.º 15
0
class GradientDescentOptimizerTest(OptimalLearningTestCase):
    r"""Test Gradient Descent on a simple quadratic objective.

    We check GD in an unconstrained setting, a constrained setting, and we test multistarting it.

    We don't test the stochastic averaging option meaningfully. We check that the optimizer will average
    the number of steps specified by input. We also check that the simple unconstrained case can also be solved
    with averaging on\*.

    \* This is not much of a test. The problem is convex and isotropic so GD will take a more or less straight
    path to the maxima. Averaging can only reduce the accuracy of the solve.

    TODO(GH-179): Build a simple stochastic objective and test the stochastic component fully.

    """
    @T.class_setup
    def base_setup(self):
        """Set up a test case for optimizing a simple quadratic polynomial."""
        self.dim = 3
        domain_bounds = [ClosedInterval(-1.0, 1.0)] * self.dim
        self.domain = TensorProductDomain(domain_bounds)

        maxima_point = numpy.full(self.dim, 0.5)
        current_point = numpy.zeros(self.dim)
        self.polynomial = QuadraticFunction(maxima_point, current_point)

        max_num_steps = 250
        max_num_restarts = 10
        num_steps_averaged = 0
        gamma = 0.7  # smaller gamma would lead to faster convergence, but we don't want to make the problem too easy
        pre_mult = 1.0
        max_relative_change = 0.8
        tolerance = 1.0e-12
        self.gd_parameters = GradientDescentParameters(
            max_num_steps,
            max_num_restarts,
            num_steps_averaged,
            gamma,
            pre_mult,
            max_relative_change,
            tolerance,
        )

        approx_grad = False
        max_func_evals = 150000
        max_metric_correc = 10
        factr = 1000.0
        pgtol = 1e-10
        epsilon = 1e-8
        self.BFGS_parameters = LBFGSBParameters(
            approx_grad,
            max_func_evals,
            max_metric_correc,
            factr,
            pgtol,
            epsilon,
        )

    def test_gradient_descent_optimizer(self):
        """Check that gradient descent can find the optimum of the quadratic test objective."""
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        gradient_descent_optimizer = GradientDescentOptimizer(
            self.domain, self.polynomial, self.gd_parameters)
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value,
                                           self.polynomial.optimum_value,
                                           tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           tolerance)

    def test_get_averaging_range(self):
        """Test the method used to produce what interval to average over in Polyak-Ruppert averaging."""
        num_steps_total = 250
        end = num_steps_total + 1
        num_steps_averaged_input_list = [
            -1, 0, 1, 20, 100, 249, 250, 251, 10000
        ]
        truth_list = [(1, end), (250, end), (250, end), (231, end), (151, end),
                      (2, end), (1, end), (1, end), (1, end)]

        for i, truth in enumerate(truth_list):
            start, end = GradientDescentOptimizer._get_averaging_range(
                num_steps_averaged_input_list[i], num_steps_total)
            T.assert_equal(start, truth[0])
            T.assert_equal(end, truth[1])

    def test_gradient_descent_optimizer_with_averaging(self):
        """Check that gradient descent can find the optimum of the quadratic test objective with averaging on.

        This test doesn't exercise the purpose of averaging (i.e., this objective isn't stochastic), but it does
        check that it at least runs.

        """
        num_steps_averaged = self.gd_parameters.max_num_steps * 3 / 4
        gd_parameters_averaging = GradientDescentParameters(
            self.gd_parameters.max_num_steps,
            self.gd_parameters.max_num_restarts,
            num_steps_averaged,
            self.gd_parameters.gamma,
            self.gd_parameters.pre_mult,
            self.gd_parameters.max_relative_change,
            self.gd_parameters.tolerance,
        )
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        gradient_descent_optimizer = GradientDescentOptimizer(
            self.domain, self.polynomial, gd_parameters_averaging)
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-10
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value,
                                           self.polynomial.optimum_value,
                                           tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           tolerance)

    def test_gradient_descent_optimizer_constrained(self):
        """Check that gradient descent can find the global optimum (in a domain) when the true optimum is outside."""
        # Domain where the optimum, (0.5, 0.5, 0.5), lies outside the domain
        domain_bounds = [
            ClosedInterval(0.05, 0.32),
            ClosedInterval(0.05, 0.6),
            ClosedInterval(0.05, 0.32)
        ]
        domain = TensorProductDomain(domain_bounds)
        gradient_descent_optimizer = GradientDescentOptimizer(
            domain, self.polynomial, self.gd_parameters)

        # Work out what the maxima point woudl be given the domain constraints (i.e., project to the nearest point on domain)
        constrained_optimum_point = self.polynomial.optimum_point
        for i, bounds in enumerate(domain_bounds):
            if constrained_optimum_point[i] > bounds.max:
                constrained_optimum_point[i] = bounds.max
            elif constrained_optimum_point[i] < bounds.min:
                constrained_optimum_point[i] = bounds.min

        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        gradient_descent_optimizer.objective_function.current_point = initial_guess
        initial_value = gradient_descent_optimizer.objective_function.compute_objective_function(
        )
        gradient_descent_optimizer.optimize()
        output = gradient_descent_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, constrained_optimum_point,
                                           tolerance)

        # Verify optimized value is better than initial guess
        final_value = self.polynomial.compute_objective_function()
        T.assert_gt(final_value, initial_value)

        # Verify derivative: only get 0 derivative if the coordinate lies inside domain boundaries
        gradient = self.polynomial.compute_grad_objective_function()
        for i, bounds in enumerate(domain_bounds):
            if bounds.is_inside(self.polynomial.optimum_point[i]):
                self.assert_scalar_within_relative(gradient[i], 0.0, tolerance)

    def test_multistarted_gradient_descent_optimizer_crippled_start(self):
        """Check that multistarted GD is finding the best result from GD."""
        # Only allow 1 GD iteration.
        gd_parameters_crippled = GradientDescentParameters(
            1,
            1,
            self.gd_parameters.num_steps_averaged,
            self.gd_parameters.gamma,
            self.gd_parameters.pre_mult,
            self.gd_parameters.max_relative_change,
            self.gd_parameters.tolerance,
        )
        gradient_descent_optimizer_crippled = GradientDescentOptimizer(
            self.domain, self.polynomial, gd_parameters_crippled)

        num_points = 15
        points = self.domain.generate_uniform_random_points_in_domain(
            num_points)

        multistart_optimizer = MultistartOptimizer(
            gradient_descent_optimizer_crippled, num_points)
        test_best_point, _ = multistart_optimizer.optimize(
            random_starts=points)
        # This point set won't include the optimum so multistart GD won't find it.
        for value in (test_best_point - self.polynomial.optimum_point):
            T.assert_not_equal(value, 0.0)

        points_with_opt = numpy.append(points,
                                       self.polynomial.optimum_point.reshape(
                                           (1, self.polynomial.dim)),
                                       axis=0)
        test_best_point, _ = multistart_optimizer.optimize(
            random_starts=points_with_opt)
        # This point set will include the optimum so multistart GD will find it.
        for value in (test_best_point - self.polynomial.optimum_point):
            T.assert_equal(value, 0.0)

    def test_multistarted_gradient_descent_optimizer(self):
        """Check that multistarted GD can find the optimum in a 'very' large domain."""
        # Set a large domain: a single GD run is unlikely to reach the optimum
        domain_bounds = [ClosedInterval(-10.0, 10.0)] * self.dim
        domain = TensorProductDomain(domain_bounds)

        tolerance = 2.0e-10
        num_points = 10
        gradient_descent_optimizer = GradientDescentOptimizer(
            domain, self.polynomial, self.gd_parameters)
        multistart_optimizer = MultistartOptimizer(gradient_descent_optimizer,
                                                   num_points)

        output, _ = multistart_optimizer.optimize()
        # Verify coordinates
        self.assert_vector_within_relative(output,
                                           self.polynomial.optimum_point,
                                           tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value,
                                           self.polynomial.optimum_value,
                                           tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           tolerance)

    def test_bfgs_optimizer(self):
        """Check that BFGS can find the optimum of the quadratic test objective."""
        # Check the claimed optima is an optima
        optimum_point = self.polynomial.optimum_point
        self.polynomial.current_point = optimum_point
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           0.0)

        # Verify that gradient descent does not move from the optima if we start it there.
        bfgs_optimizer = LBFGSBOptimizer(self.domain, self.polynomial,
                                         self.BFGS_parameters)
        bfgs_optimizer.optimize()
        output = bfgs_optimizer.objective_function.current_point
        self.assert_vector_within_relative(output, optimum_point, 0.0)

        # Start at a wrong point and check optimization
        tolerance = 2.0e-13
        initial_guess = numpy.full(self.polynomial.dim, 0.2)
        bfgs_optimizer.objective_function.current_point = initial_guess
        bfgs_optimizer.optimize()
        output = bfgs_optimizer.objective_function.current_point
        # Verify coordinates
        self.assert_vector_within_relative(output, optimum_point, tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value,
                                           self.polynomial.optimum_value,
                                           tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           tolerance)

    def test_multistarted_bfgs_optimizer(self):
        """Check that multistarted GD can find the optimum in a 'very' large domain."""
        # Set a large domain: a single GD run is unlikely to reach the optimum
        domain_bounds = [ClosedInterval(-10.0, 10.0)] * self.dim
        domain = TensorProductDomain(domain_bounds)

        tolerance = 2.0e-10
        num_points = 10
        bfgs_optimizer = LBFGSBOptimizer(domain, self.polynomial,
                                         self.BFGS_parameters)
        multistart_optimizer = MultistartOptimizer(bfgs_optimizer, num_points)

        output, _ = multistart_optimizer.optimize()
        # Verify coordinates
        self.assert_vector_within_relative(output,
                                           self.polynomial.optimum_point,
                                           tolerance)

        # Verify function value
        value = self.polynomial.compute_objective_function()
        self.assert_scalar_within_relative(value,
                                           self.polynomial.optimum_value,
                                           tolerance)

        # Verify derivative
        gradient = self.polynomial.compute_grad_objective_function()
        self.assert_vector_within_relative(gradient,
                                           numpy.zeros(self.polynomial.dim),
                                           tolerance)