code: def test_gp(self):
      d = 3
      bounds = torch.tensor([[-1.0] * d, [1.0] * d])
      for batch_shape, m, ncat, dtype, observed_noise in (
          (torch.Size(), 1, 0, torch.float, False),
          (torch.Size(), 2, 1, torch.double, True),
          (torch.Size([2]), 2, 3, torch.double, False),
      ):
          tkwargs = {"device": self.device, "dtype": dtype}
          train_X, train_Y = _get_random_data(
              batch_shape=batch_shape, m=m, d=d, **tkwargs
          )
          cat_dims = list(range(ncat))
          ord_dims = sorted(set(range(d)) - set(cat_dims))
          # test correct indices
          if (ncat < 3) and (ncat > 0):
              MixedSingleTaskGP(
                  train_X,
                  train_Y,
                  cat_dims=cat_dims,
                  input_transform=Normalize(
                      d=d,
                      bounds=bounds.to(**tkwargs),
                      transform_on_train=True,
                      indices=ord_dims,
                  ),
              )
  
          if len(cat_dims) == 0:
              with self.assertRaises(ValueError):
                  MixedSingleTaskGP(train_X, train_Y, cat_dims=cat_dims)
              continue
  
          train_Yvar = (
              torch.full_like(train_Y, 0.1) if observed_noise else None
          )
          model = MixedSingleTaskGP(
              train_X=train_X,
              train_Y=train_Y,
              cat_dims=cat_dims,
              train_Yvar=train_Yvar,
          )
          self.assertEqual(model._ignore_X_dims_scaling_check, cat_dims)
          mll = ExactMarginalLogLikelihood(model.likelihood, model).to(
              **tkwargs
          )
          with warnings.catch_warnings():
              warnings.filterwarnings(
                  "ignore", category=OptimizationWarning
              )
              fit_gpytorch_mll(
                  mll,
                  optimizer_kwargs={"options": {"maxiter": 1}},
                  max_attempts=1,
              )
  
          # test init
          self.assertIsInstance(model.mean_module, ConstantMean)
          if ncat < 3:
              self.assertIsInstance(model.covar_module, AdditiveKernel)
              sum_kernel, prod_kernel = model.covar_module.kernels
              self.assertIsInstance(sum_kernel, ScaleKernel)
              self.assertIsInstance(
                  sum_kernel.base_kernel, AdditiveKernel
              )
              self.assertIsInstance(prod_kernel, ScaleKernel)
              self.assertIsInstance(
                  prod_kernel.base_kernel, ProductKernel
              )
              (
                  sum_cont_kernel,
                  sum_cat_kernel,
              ) = sum_kernel.base_kernel.kernels
              (
                  prod_cont_kernel,
                  prod_cat_kernel,
              ) = prod_kernel.base_kernel.kernels
              self.assertIsInstance(sum_cont_kernel, MaternKernel)
              self.assertIsInstance(sum_cat_kernel, ScaleKernel)
              self.assertIsInstance(
                  sum_cat_kernel.base_kernel, CategoricalKernel
              )
              self.assertIsInstance(prod_cont_kernel, MaternKernel)
              self.assertIsInstance(prod_cat_kernel, CategoricalKernel)
          else:
              self.assertIsInstance(model.covar_module, ScaleKernel)
              self.assertIsInstance(
                  model.covar_module.base_kernel, CategoricalKernel
              )
          if observed_noise:
              self.assertIsInstance(
                  model.likelihood, FixedNoiseGaussianLikelihood
              )
          else:
              self.assertIsInstance(
                  model.likelihood, GaussianLikelihood
              )
  
          # test posterior
          # test non batch evaluation
          X = torch.rand(batch_shape + torch.Size([4, d]), **tkwargs)
          expected_shape = batch_shape + torch.Size([4, m])
          posterior = model.posterior(X)
          self.assertIsInstance(posterior, GPyTorchPosterior)
          self.assertEqual(posterior.mean.shape, expected_shape)
          self.assertEqual(posterior.variance.shape, expected_shape)
  
          # test adding observation noise
          posterior_pred = model.posterior(X, observation_noise=True)
          self.assertIsInstance(posterior_pred, GPyTorchPosterior)
          self.assertEqual(posterior_pred.mean.shape, expected_shape)
          self.assertEqual(
              posterior_pred.variance.shape, expected_shape
          )
          pvar = posterior_pred.variance
          pvar_exp = get_pvar_expected(posterior, model, X, m)
          self.assertAllClose(pvar, pvar_exp, rtol=1e-4, atol=1e-5)
  
          # test batch evaluation
          X = torch.rand(2, *batch_shape, 3, d, **tkwargs)
          expected_shape = (
              torch.Size([2]) + batch_shape + torch.Size([3, m])
          )
          posterior = model.posterior(X)
          self.assertIsInstance(posterior, GPyTorchPosterior)
          self.assertEqual(posterior.mean.shape, expected_shape)
          # test adding observation noise in batch mode
          posterior_pred = model.posterior(X, observation_noise=True)
          self.assertIsInstance(posterior_pred, GPyTorchPosterior)
          self.assertEqual(posterior_pred.mean.shape, expected_shape)
          pvar = posterior_pred.variance
          pvar_exp = get_pvar_expected(posterior, model, X, m)
          self.assertAllClose(pvar, pvar_exp, rtol=1e-4, atol=1e-5)
  
          # test that model converter throws an exception
          with self.assertRaisesRegex(
              NotImplementedError, "not supported"
          ):
              batched_to_model_list(model)
  
imports: import itertools
  import warnings
  import torch
  from botorch.exceptions.warnings import OptimizationWarning
  from botorch.fit import fit_gpytorch_mll
  from botorch.models.converter import batched_to_model_list
  from botorch.models.gp_regression_mixed import MixedSingleTaskGP
  from botorch.models.kernels.categorical import CategoricalKernel
  from botorch.models.transforms import Normalize
  from botorch.posteriors import GPyTorchPosterior
  from botorch.sampling import SobolQMCNormalSampler
  from botorch.utils.datasets import SupervisedDataset
  from botorch.utils.test_helpers import get_pvar_expected
  from botorch.utils.testing import _get_random_data, BotorchTestCase
  from gpytorch.kernels.kernel import AdditiveKernel, ProductKernel
  from gpytorch.kernels.matern_kernel import MaternKernel
  from gpytorch.kernels.scale_kernel import ScaleKernel
  from gpytorch.likelihoods import FixedNoiseGaussianLikelihood
  from gpytorch.likelihoods.gaussian_likelihood import GaussianLikelihood
  from gpytorch.means import ConstantMean
  from gpytorch.mlls.exact_marginal_log_likelihood import ExactMarginalLogLikelihood
label_desc: Use image node_id 1 for calling the TestMixedSingleTaskGP obj's underlying member method code with example usage: obj.test_gp() without return types