class_docstr: Implement the acquisition function of Sparsity Exploring Bayesian
  Optimization (SEBO).
  
  The SEBO is a hyperparameter-free method to simultaneously maximize a target
  objective and sparsity. When L0 norm is used, SEBO uses a novel differentiable
  relaxation based on homotopy continuation to efficiently optimize for sparsity.
class_docstr_tok: ["Implement","the","acquisition","function","of","Sparsity","Exploring","Bayesian","Optimization","(","SEBO",")",".","The","SEBO","is","a","hyperparameter-free","method","to","simultaneously","maximize","a","target","objective","and","sparsity",".","When","L0","norm","is","used",",","SEBO","uses","a","novel","differentiable","relaxation","based","on","homotopy","continuation","to","efficiently","optimize","for","sparsity","."]
code: def __init__(
      self,
      surrogates: Dict[str, Surrogate],
      search_space_digest: SearchSpaceDigest,
      torch_opt_config: TorchOptConfig,
      botorch_acqf_class: Type[AcquisitionFunction],
      options: Optional[Dict[str, Any]] = None,
  ) -> None:
      if len(surrogates) > 1:
          raise ValueError(
              "SEBO does not support support multiple surrogates."
          )
      surrogate = surrogates[Keys.ONLY_SURROGATE]
  
      tkwargs: Dict[str, Any] = {
          "dtype": surrogate.dtype,
          "device": surrogate.device,
      }
      options = options or {}
      self.penalty_name: str = options.pop("penalty", "L0_norm")
      self.target_point: Tensor = options.pop("target_point", None)
      if self.target_point is None:
          raise ValueError("please provide target point.")
      self.target_point.to(**tkwargs)
      self.sparsity_threshold: int = options.pop(
          "sparsity_threshold", surrogate.Xs[0].shape[-1]
      )
      # construct determinsitic model for penalty term
      # pyre-fixme[4]: Attribute must be annotated.
      self.deterministic_model = self._construct_penalty()
  
      surrogate_f = deepcopy(surrogate)
      # update the training data in new surrogate
      not_none(surrogate_f._training_data).append(
          SupervisedDataset(
              surrogate_f.Xs[0],
              self.deterministic_model(surrogate_f.Xs[0]),
              # append Yvar as zero for penalty term
              Yvar=torch.zeros(
                  surrogate_f.Xs[0].shape[0], 1, **tkwargs
              ),
              feature_names=surrogate_f.training_data[0].feature_names,
              outcome_names=[self.penalty_name],
          )
      )
      # update the model in new surrogate
      surrogate_f._model = ModelList(
          surrogate.model, self.deterministic_model
      )
      self.det_metric_indx = -1
  
      # update objective weights and  thresholds in the torch config
      torch_opt_config_sebo = self._transform_torch_config(
          torch_opt_config, **tkwargs
      )
  
      # instantiate botorch_acqf_class
      if not issubclass(
          botorch_acqf_class, qExpectedHypervolumeImprovement
      ):
          raise ValueError(
              "botorch_acqf_class must be qEHVI to use SEBO"
          )
      super().__init__(
          surrogates={"sebo": surrogate_f},
          search_space_digest=search_space_digest,
          torch_opt_config=torch_opt_config_sebo,
          botorch_acqf_class=botorch_acqf_class,
          options=options,
      )
      if not isinstance(self.acqf, qExpectedHypervolumeImprovement):
          raise ValueError(
              "botorch_acqf_class must be qEHVI to use SEBO"
          )
  
      # update objective threshold for deterministic model (penalty term)
      self.acqf.ref_point[-1] = self.sparsity_threshold * -1
      # pyre-ignore
      self._objective_thresholds[-1] = self.sparsity_threshold
  
      Y_pareto = torch.cat(
          [d.Y for d in self.surrogates["sebo"].training_data],
          dim=-1,
      )
      ind_pareto = is_non_dominated(
          Y_pareto * self._full_objective_weights
      )
      # pyre-ignore
      self.X_pareto = self.surrogates["sebo"].Xs[0][ind_pareto].clone()
  
imports: import functools
  from copy import deepcopy
  from functools import partial
  from typing import Any, Callable, Dict, List, Optional, Tuple, Type
  import torch
  from ax.core.search_space import SearchSpaceDigest
  from ax.models.torch.botorch_modular.acquisition import Acquisition
  from ax.models.torch.botorch_modular.optimizer_argparse import optimizer_argparse
  from ax.models.torch.botorch_modular.surrogate import Surrogate
  from ax.models.torch_base import TorchOptConfig
  from ax.utils.common.constants import Keys
  from ax.utils.common.typeutils import not_none
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.acquisition.multi_objective.monte_carlo import qExpectedHypervolumeImprovement
  from botorch.acquisition.penalized import L0Approximation
  from botorch.models.deterministic import GenericDeterministicModel
  from botorch.models.model import ModelList
  from botorch.optim import Homotopy, HomotopyParameter, LogLinearHomotopySchedule, optimize_acqf_homotopy
  from botorch.utils.datasets import SupervisedDataset
  from botorch.utils.multi_objective.pareto import is_non_dominated
  from torch import Tensor
  from torch.quasirandom import SobolEngine
label_desc: Use image node_id 1 to create a new SEBOAcquisition object from inherited base classes: Acquisition with example: obj = SEBOAcquisition(surrogates, search_space_digest, torch_opt_config, botorch_acqf_class, options)