code: def get_acqf(
      acquisition_function_name: str,
  ) -> Callable[[Callable[[], None]], TAcqfConstructor]:
      """Returns a decorator whose wrapper function instantiates an acquisition function.
  
      NOTE: This is a decorator factory instead of a simple factory as serialization
      of Botorch model kwargs requires callables to be have module-level paths, and
      closures created by a simple factory do not have such paths. We solve this by
      wrapping "empty" module-level functions with this decorator, we ensure that they
      are serialized correctly, in addition to reducing code duplication.
  
      Example:
          >>> @get_acqf("qEI")
          ... def get_qEI() -> None:
          ...     pass
          >>> acqf = get_qEI(
          ...     model=model,
          ...     objective_weights=objective_weights,
          ...     outcome_constraints=outcome_constraints,
          ...     X_observed=X_observed,
          ...     X_pending=X_pending,
          ...     **kwargs,
          ... )
          >>> type(acqf)
          ... botorch.acquisition.monte_carlo.qExpectedImprovement
  
      Args:
          acquisition_function_name: The name of the acquisition function to be
              instantiated by the returned function.
  
      Returns:
          A decorator whose wrapper function is a TAcqfConstructor, i.e. it requires a
          `model`, `objective_weights`, and optional `outcome_constraints`, `X_observed`,
          and `X_pending` as inputs, as well as `kwargs`, and returns an
          `AcquisitionFunction` instance that corresponds to `acquisition_function_name`.
      """
  
      def decorator(
          empty_acqf_getter: Callable[[], None]
      ) -> TAcqfConstructor:
          # `wraps` allows the function to keep its original, module-level name, enabling
          # serialization via `callable_to_reference`. `empty_acqf_getter` is otherwise
          # not used in the wrapper.
          @functools.wraps(empty_acqf_getter)
          def wrapper(
              model: Model,
              objective_weights: Tensor,
              outcome_constraints: Optional[
                  Tuple[Tensor, Tensor]
              ] = None,
              X_observed: Optional[Tensor] = None,
              X_pending: Optional[Tensor] = None,
              **kwargs: Any,
          ) -> AcquisitionFunction:
              kwargs.pop("objective_thresholds", None)
              return _get_acquisition_func(
                  model=model,
                  acquisition_function_name=acquisition_function_name,
                  objective_weights=objective_weights,
                  outcome_constraints=outcome_constraints,
                  X_observed=X_observed,
                  X_pending=X_pending,
                  **kwargs,
              )
  
          return wrapper
  
      return decorator
  
imports: import functools
  from copy import deepcopy
  from random import randint
  from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Type, Union
  import torch
  from ax.models.model_utils import best_observed_point, get_observed
  from ax.models.torch.utils import _to_inequality_constraints
  from ax.models.torch_base import TorchModel
  from ax.models.types import TConfig
  from botorch.acquisition import get_acquisition_function
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.acquisition.fixed_feature import FixedFeatureAcquisitionFunction
  from botorch.acquisition.objective import ConstrainedMCObjective, GenericMCObjective
  from botorch.acquisition.utils import get_infeasible_cost
  from botorch.exceptions.errors import UnsupportedError
  from botorch.fit import fit_gpytorch_mll
  from botorch.models.gp_regression import SingleTaskGP
  from botorch.models.gp_regression_fidelity import SingleTaskMultiFidelityGP
  from botorch.models.gpytorch import GPyTorchModel
  from botorch.models.model import Model
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.models.transforms.input import Warp
  from botorch.optim.optimize import optimize_acqf
  from botorch.utils import get_objective_weights_transform, get_outcome_constraint_transforms
  from botorch.utils.multi_objective.scalarization import get_chebyshev_scalarization
  from botorch.utils.transforms import is_ensemble
  from gpytorch.kernels import MaternKernel, ScaleKernel
  from gpytorch.kernels.kernel import Kernel
  from gpytorch.mlls.exact_marginal_log_likelihood import ExactMarginalLogLikelihood
  from gpytorch.mlls.leave_one_out_pseudo_likelihood import LeaveOneOutPseudoLikelihood
  from gpytorch.mlls.sum_marginal_log_likelihood import SumMarginalLogLikelihood
  from gpytorch.priors import Prior
  from gpytorch.priors.lkj_prior import LKJCovariancePrior
  from gpytorch.priors.torch_priors import GammaPrior, LogNormalPrior
  from torch import Tensor
label_desc: Use image node_id 3 for calling a global function with example usage: get_acqf(acquisition_function_name) and returns: decorator, wrapper, _get_acquisition_func