code: def convert_to_block_design(
      datasets: List[SupervisedDataset],
      force: bool = False,
  ) -> List[SupervisedDataset]:
      # Convert data to "block design". TODO: Figure out a better
      # solution for this using the data containers (pass outcome
      # names as properties of the data containers)
      is_fixed = [ds.Yvar is not None for ds in datasets]
      if any(is_fixed) and not all(is_fixed):
          raise UnsupportedError(
              "Cannot convert mixed data with and without variance "
              "observaitons to `block design`."
          )
      is_fixed = all(is_fixed)
      Xs = [dataset.X for dataset in datasets]
      for dset in datasets[1:]:
          if dset.feature_names != datasets[0].feature_names:
              raise ValueError(
                  "Feature names must be the same across all datasets, "
                  f"got {dset.feature_names} and {datasets[0].feature_names}"
              )
  
      # Join the outcome names of datasets.
      outcome_names = sum([ds.outcome_names for ds in datasets], [])
  
      if len({X.shape for X in Xs}) != 1 or not all(
          torch.equal(X, Xs[0]) for X in Xs[1:]
      ):
          if not force:
              raise UnsupportedError(
                  "Cannot convert data to non-block design data. "
                  "To force this and drop data not shared between "
                  "outcomes use `force=True`."
              )
          warnings.warn(
              "Forcing converion of data not complying to a block design "
              "to block design by dropping observations that are not shared "
              "between outcomes.",
              AxWarning,
          )
          X_shared, idcs_shared = _get_shared_rows(Xs=Xs)
          Y = torch.cat(
              [ds.Y[i] for ds, i in zip(datasets, idcs_shared)], dim=-1
          )
          if is_fixed:
              Yvar = torch.cat(
                  [ds.Yvar[i] for ds, i in zip(datasets, idcs_shared)],
                  dim=-1,
              )
          else:
              Yvar = None
          datasets = [
              SupervisedDataset(
                  X=X_shared,
                  Y=Y,
                  Yvar=Yvar,
                  feature_names=datasets[0].feature_names,
                  outcome_names=outcome_names,
              )
          ]
          return datasets
  
      # data complies to block design, can concat with impunity
      Y = torch.cat([ds.Y for ds in datasets], dim=-1)
      if is_fixed:
          Yvar = torch.cat(
              [not_none(ds.Yvar) for ds in datasets], dim=-1
          )
      else:
          Yvar = None
      datasets = [
          SupervisedDataset(
              X=Xs[0],
              Y=Y,
              Yvar=Yvar,
              feature_names=datasets[0].feature_names,
              outcome_names=outcome_names,
          )
      ]
      return datasets
  
imports: import warnings
  from logging import Logger
  from typing import Any, Callable, Dict, List, Optional, OrderedDict, Tuple, Type
  import torch
  from ax.core.search_space import SearchSpaceDigest
  from ax.exceptions.core import AxError, AxWarning, UnsupportedError
  from ax.models.types import TConfig
  from ax.utils.common.constants import Keys
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast, not_none
  from botorch.acquisition.acquisition import AcquisitionFunction
  from botorch.acquisition.logei import qLogNoisyExpectedImprovement
  from botorch.acquisition.multi_objective.logei import qLogNoisyExpectedHypervolumeImprovement
  from botorch.fit import fit_fully_bayesian_model_nuts, fit_gpytorch_mll
  from botorch.models.fully_bayesian import SaasFullyBayesianSingleTaskGP
  from botorch.models.gp_regression import SingleTaskGP
  from botorch.models.gp_regression_fidelity import SingleTaskMultiFidelityGP
  from botorch.models.gp_regression_mixed import MixedSingleTaskGP
  from botorch.models.gpytorch import BatchedMultiOutputGPyTorchModel, GPyTorchModel
  from botorch.models.model import Model, ModelList
  from botorch.models.multitask import MultiTaskGP
  from botorch.models.pairwise_gp import PairwiseGP
  from botorch.utils.datasets import SupervisedDataset
  from botorch.utils.transforms import is_fully_bayesian
  from gpytorch.mlls.marginal_log_likelihood import MarginalLogLikelihood
  from torch import Tensor
label_desc: Use image node_id 5 for calling a global function with example usage: convert_to_block_design(datasets, force) and returns: datasets, datasets