class_docstr: Does Bayesian optimization with structural additive contextual GP (SACGP).
  The parameter space decomposition must be provided.
  
  Args:
      decomposition: Keys are context names. Values are the lists of parameter
          names belong to the context, e.g.
          {'context1': ['p1_c1', 'p2_c1'],'context2': ['p1_c2', 'p2_c2']}.
class_docstr_tok: ["Does","Bayesian","optimization","with","structural","additive","contextual","GP","(","SACGP",")",".","The","parameter","space","decomposition","must","be","provided",".","Args",":","decomposition",":","Keys","are","context","names",".","Values","are","the","lists","of","parameter","names","belong","to","the","context",",","e.g",".","{","'context1","'",":","[","'p1_c1","'",",","'p2_c1","'","]",",","'context2","'",":","[","'p1_c2","'",",","'p2_c2","'","]","}","."]
code: def __init__(self, decomposition: Dict[str, List[str]]) -> None:
      # add validation for input decomposition
      for param_list in decomposition.values():
          assert len(param_list) == len(
              list(decomposition.values())[0]
          ), "Each Context must contain same number of parameters"
      self.decomposition = decomposition
      self.feature_names: List[str] = []
      super().__init__(model_constructor=self.get_and_fit_model)
  
imports: from logging import Logger
  from typing import Any, Dict, List, Optional
  from ax.core.search_space import SearchSpaceDigest
  from ax.core.types import TCandidateMetadata
  from ax.models.torch.botorch import BotorchModel
  from ax.models.torch_base import TorchModel
  from ax.utils.common.docutils import copy_doc
  from ax.utils.common.logger import get_logger
  from botorch.fit import fit_gpytorch_mll
  from botorch.models.contextual import SACGP
  from botorch.models.gpytorch import GPyTorchModel
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.utils.datasets import SupervisedDataset
  from gpytorch.mlls.exact_marginal_log_likelihood import ExactMarginalLogLikelihood
  from torch import Tensor
label_desc: Use image node_id 1 to create a new SACBO object from inherited base classes: BotorchModel with example: obj = SACBO(decomposition)