class_docstr: Benchmark problem, represented in terms of Ax search space, optimization
  config, and runner.
docstr: Create a BenchmarkProblem from a BoTorch BaseTestProblem using
  specialized Metrics and Runners. The test problem's result will be
  computed on the Runner and retrieved by the Metric.
  
  Args:
      test_problem_class: The BoTorch test problem class which will be
          used to define the `search_space`, `optimization_config`, and
          `runner`.
      test_problem_kwargs: Keyword arguments used to instantiate the
          `test_problem_class`.
      num_trials: Simply the `num_trials` of the `BenchmarkProblem`
          created.
      infer_noise: Whether noise will be inferred. This is separate from
          whether synthetic noise is added to the problem, which is
          controlled by the `noise_std` of the test problem.
code: def from_botorch(
      cls,
      test_problem_class: Type[BaseTestProblem],
      test_problem_kwargs: Dict[str, Any],
      num_trials: int,
      infer_noise: bool = True,
  ) -> "BenchmarkProblem":
      """
      Create a BenchmarkProblem from a BoTorch BaseTestProblem using
      specialized Metrics and Runners. The test problem's result will be
      computed on the Runner and retrieved by the Metric.
  
      Args:
          test_problem_class: The BoTorch test problem class which will be
              used to define the `search_space`, `optimization_config`, and
              `runner`.
          test_problem_kwargs: Keyword arguments used to instantiate the
              `test_problem_class`.
          num_trials: Simply the `num_trials` of the `BenchmarkProblem`
              created.
          infer_noise: Whether noise will be inferred. This is separate from
              whether synthetic noise is added to the problem, which is
              controlled by the `noise_std` of the test problem.
      """
  
      # pyre-fixme [45]: Invalid class instantiation
      test_problem = test_problem_class(**test_problem_kwargs)
      is_constrained = isinstance(
          test_problem, ConstrainedBaseTestProblem
      )
  
      search_space = SearchSpace(
          parameters=[
              RangeParameter(
                  name=f"x{i}",
                  parameter_type=ParameterType.FLOAT,
                  lower=test_problem._bounds[i][0],
                  upper=test_problem._bounds[i][1],
              )
              for i in range(test_problem.dim)
          ]
      )
  
      dim = test_problem_kwargs.get("dim", None)
      name = _get_name(test_problem, infer_noise, dim)
  
      if infer_noise:
          noise_sd = None
      elif isinstance(test_problem.noise_std, list):
          # Convention is to have the first outcome be the objective,
          # and the remaining ones the constraints.
          noise_sd = test_problem.noise_std[0]
      else:
          noise_sd = checked_cast(float, test_problem.noise_std or 0.0)
  
      # TODO: Support constrained MOO problems.
  
      objective = Objective(
          metric=BotorchTestProblemMetric(
              name=name,
              noise_sd=noise_sd,
              index=0,
          ),
          minimize=True,
      )
  
      if is_constrained:
          n_con = test_problem.num_constraints
          if infer_noise:
              constraint_noise_sds = [None] * n_con
          elif test_problem.constraint_noise_std is None:
              constraint_noise_sds = [0.0] * n_con
          elif isinstance(test_problem.constraint_noise_std, list):
              constraint_noise_sds = test_problem.constraint_noise_std[
                  :n_con
              ]
          else:
              constraint_noise_sds = [
                  test_problem.constraint_noise_std
              ] * n_con
  
          outcome_constraints = [
              OutcomeConstraint(
                  metric=BotorchTestProblemMetric(
                      name=f"constraint_slack_{i}",
                      noise_sd=constraint_noise_sds[i],
                      index=i,
                  ),
                  op=ComparisonOp.GEQ,
                  bound=0.0,
                  relative=False,
              )
              for i in range(n_con)
          ]
  
      else:
          outcome_constraints = []
  
      optimization_config = OptimizationConfig(
          objective=objective,
          outcome_constraints=outcome_constraints,
      )
  
      return cls(
          name=name,
          search_space=search_space,
          optimization_config=optimization_config,
          runner=BotorchTestProblemRunner(
              test_problem_class=test_problem_class,
              test_problem_kwargs=test_problem_kwargs,
          ),
          num_trials=num_trials,
          infer_noise=infer_noise,
      )
  
imports: import abc
  from typing import Any, Dict, List, Optional, Protocol, runtime_checkable, Type
  from ax.core.metric import Metric
  from ax.core.objective import MultiObjective, Objective
  from ax.core.optimization_config import MultiObjectiveOptimizationConfig, ObjectiveThreshold, OptimizationConfig
  from ax.core.outcome_constraint import OutcomeConstraint
  from ax.core.parameter import ParameterType, RangeParameter
  from ax.core.runner import Runner
  from ax.core.search_space import SearchSpace
  from ax.core.types import ComparisonOp
  from ax.metrics.botorch_test_problem import BotorchTestProblemMetric
  from ax.runners.botorch_test_problem import BotorchTestProblemRunner
  from ax.utils.common.base import Base
  from ax.utils.common.typeutils import checked_cast
  from botorch.test_functions.base import BaseTestProblem, ConstrainedBaseTestProblem
  from botorch.test_functions.multi_objective import MultiObjectiveTestProblem
  from botorch.test_functions.synthetic import SyntheticTestFunction
label_desc: Use image node_id 3 for calling the BenchmarkProblem obj's underlying member method code with example usage: obj.from_botorch(cls, test_problem_class, test_problem_kwargs, num_trials, infer_noise) and returns: cls