code: def test_convert_to_block_design(self) -> None:
      # simple case: block design, supervised
      X = torch.rand(4, 2)
      Ys = [torch.rand(4, 1), torch.rand(4, 1)]
      metric_names = ["y1", "y2"]
      datasets = [
          SupervisedDataset(
              X=X,
              Y=Ys[i],
              feature_names=["x1", "x2"],
              outcome_names=[metric_names[i]],
          )
          for i in range(2)
      ]
      new_datasets = convert_to_block_design(datasets=datasets)
      self.assertEqual(len(new_datasets), 1)
      self.assertIsInstance(new_datasets[0], SupervisedDataset)
      self.assertTrue(torch.equal(new_datasets[0].X, X))
      self.assertTrue(
          torch.equal(new_datasets[0].Y, torch.cat(Ys, dim=-1))
      )
      self.assertEqual(new_datasets[0].outcome_names, metric_names)
  
      # simple case: block design, fixed
      Yvars = [torch.rand(4, 1), torch.rand(4, 1)]
      datasets = [
          SupervisedDataset(
              X=X,
              Y=Ys[i],
              Yvar=Yvars[i],
              feature_names=["x1", "x2"],
              outcome_names=[metric_names[i]],
          )
          for i in range(2)
      ]
      new_datasets = convert_to_block_design(datasets=datasets)
      self.assertEqual(len(new_datasets), 1)
      self.assertIsNotNone(new_datasets[0].Yvar)
      self.assertTrue(torch.equal(new_datasets[0].X, X))
      self.assertTrue(
          torch.equal(new_datasets[0].Y, torch.cat(Ys, dim=-1))
      )
      self.assertTrue(
          torch.equal(
              not_none(new_datasets[0].Yvar), torch.cat(Yvars, dim=-1)
          )
      )
      self.assertEqual(new_datasets[0].outcome_names, metric_names)
  
      # test error is raised if not block design and force=False
      X2 = torch.cat((X[:3], torch.rand(1, 2)))
      datasets = [
          SupervisedDataset(
              X=X, Y=Y, feature_names=["x1", "x2"], outcome_names=[name]
          )
          for X, Y, name in zip((X, X2), Ys, metric_names)
      ]
      with self.assertRaisesRegex(
          UnsupportedError,
          "Cannot convert data to non-block design data.",
      ):
          convert_to_block_design(datasets=datasets)
  
      # test warning is issued if not block design and force=True (supervised)
      with warnings.catch_warnings(record=True) as ws:
          new_datasets = convert_to_block_design(
              datasets=datasets, force=True
          )
      # pyre-fixme[6]: For 1st param expected `Iterable[object]` but got `bool`.
      self.assertTrue(
          any(issubclass(w.category, AxWarning)) for w in ws
      )
      self.assertTrue(
          any(
              "Forcing converion of data not complying to a block design"
              in str(w.message)
              for w in ws
          )
      )
      self.assertEqual(len(new_datasets), 1)
      self.assertIsNone(new_datasets[0].Yvar)
      self.assertTrue(torch.equal(new_datasets[0].X, X[:3]))
      self.assertTrue(
          torch.equal(
              new_datasets[0].Y, torch.cat([Y[:3] for Y in Ys], dim=-1)
          )
      )
      self.assertEqual(new_datasets[0].outcome_names, metric_names)
  
      # test warning is issued if not block design and force=True (fixed)
      datasets = [
          SupervisedDataset(
              X=X,
              Y=Y,
              Yvar=Yvar,
              feature_names=["x1", "x2"],
              outcome_names=[name],
          )
          for X, Y, Yvar, name in zip((X, X2), Ys, Yvars, metric_names)
      ]
      with warnings.catch_warnings(record=True) as ws:
          new_datasets = convert_to_block_design(
              datasets=datasets, force=True
          )
      self.assertTrue(
          any(issubclass(w.category, AxWarning) for w in ws)
      )
      self.assertTrue(
          any(
              "Forcing converion of data not complying to a block design"
              in str(w.message)
              for w in ws
          )
      )
      self.assertEqual(len(new_datasets), 1)
      self.assertIsNotNone(new_datasets[0].Yvar)
      self.assertTrue(torch.equal(new_datasets[0].X, X[:3]))
      self.assertTrue(
          torch.equal(
              new_datasets[0].Y, torch.cat([Y[:3] for Y in Ys], dim=-1)
          )
      )
      self.assertTrue(
          torch.equal(
              not_none(new_datasets[0].Yvar),
              torch.cat([Yvar[:3] for Yvar in Yvars], dim=-1),
          )
      )
      self.assertEqual(new_datasets[0].outcome_names, metric_names)
  
imports: import warnings
  from typing import OrderedDict
  import numpy
  import torch
  from ax.core.search_space import SearchSpaceDigest
  from ax.exceptions.core import AxError, AxWarning, UnsupportedError
  from ax.models.torch.botorch_modular.utils import _get_shared_rows, _tensor_difference, check_metric_dataset_match, choose_botorch_acqf_class, choose_model_class, construct_acquisition_and_optimizer_options, convert_to_block_design, get_subset_datasets, subset_state_dict, use_model_list
  from ax.models.torch.utils import _to_inequality_constraints
  from ax.utils.common.constants import Keys
  from ax.utils.common.testutils import TestCase
  from ax.utils.common.typeutils import checked_cast, not_none
  from ax.utils.testing.torch_stubs import get_torch_test_data
  from botorch.acquisition import qLogNoisyExpectedImprovement
  from botorch.acquisition.multi_objective.logei import qLogNoisyExpectedHypervolumeImprovement
  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.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.utils.datasets import SupervisedDataset
label_desc: Use image node_id 11 for calling the BoTorchModelUtilsTest obj's underlying member method code with example usage: obj.test_convert_to_block_design() without return types