docstr: Test that 'fantasize' on average recovers the true mean fn.
  
  Loose tolerance to protect against flakiness. The true mean function is
  100 at x=0. If transforms are not properly applied, we'll get answers
  on the order of ~1. Answers between 99 and 101 are acceptable.
docstr_tok: ["Test","that","'fantasize","'","on","average","recovers","the","true","mean","fn",".","Loose","tolerance","to","protect","against","flakiness",".","The","true","mean","function","is","100","at","x=0",".","If","transforms","are","not","properly","applied",",","we","'ll","get","answers","on","the","order","of","~1",".","Answers","between","99","and","101","are","acceptable","."]
code: def test_fantasize_with_outcome_transform_fixed_noise(self) -> None:
      """
      Test that 'fantasize' on average recovers the true mean fn.
  
      Loose tolerance to protect against flakiness. The true mean function is
      100 at x=0. If transforms are not properly applied, we'll get answers
      on the order of ~1. Answers between 99 and 101 are acceptable.
      """
      n_fants = torch.Size([20])
      y_at_low_x = 100.0
      y_at_high_x = -40.0
  
      for dtype in [torch.float, torch.double]:
          with self.subTest(dtype=dtype):
              tkwargs = {"device": self.device, "dtype": dtype}
              X = torch.tensor([[0.0], [1.0]], **tkwargs)
              Y = torch.tensor([[y_at_low_x], [y_at_high_x]], **tkwargs)
              Y2 = 2 * Y
              yvar = torch.full_like(Y, 1e-4)
              yvar2 = 2 * yvar
              model = ModelListGP(
                  SingleTaskGP(
                      X, Y, yvar, outcome_transform=Standardize(m=1)
                  ),
                  SingleTaskGP(
                      X, Y2, yvar2, outcome_transform=Standardize(m=1)
                  ),
              )
              # test exceptions
              eval_mask = torch.zeros(
                  3, 2, 2, dtype=torch.bool, device=tkwargs["device"]
              )
              msg = (
                  f"Expected evaluation_mask of shape `{X.shape[0]} x "
                  f"{model.num_outputs}`, but got `"
                  f"{' x '.join(str(i) for i in eval_mask.shape)}`."
              )
              with self.assertRaisesRegex(
                  BotorchTensorDimensionError, msg
              ):
                  model.fantasize(
                      X,
                      evaluation_mask=eval_mask,
                      sampler=ListSampler(
                          IIDNormalSampler(n_fants, seed=0),
                          IIDNormalSampler(n_fants, seed=0),
                      ),
                  )
              msg = (
                  "Decoupled fantasization requires a list of samplers."
              )
              with self.assertRaisesRegex(ValueError, msg):
                  model.fantasize(
                      X,
                      evaluation_mask=eval_mask[0],
                      sampler=IIDNormalSampler(n_fants, seed=0),
                  )
              model.posterior(torch.zeros((1, 1), **tkwargs))
              for decoupled in (False, True):
                  if decoupled:
                      kwargs = {
                          "sampler": ListSampler(
                              IIDNormalSampler(n_fants, seed=0),
                              IIDNormalSampler(n_fants, seed=0),
                          ),
                          "evaluation_mask": torch.tensor(
                              [[0, 1], [1, 0]],
                              dtype=torch.bool,
                              device=tkwargs["device"],
                          ),
                      }
                  else:
                      kwargs = {
                          "sampler": IIDNormalSampler(n_fants, seed=0),
                      }
                  fant = model.fantasize(X, **kwargs)
  
                  fant_mean = fant.posterior(X).mean.mean(0)
                  self.assertAlmostEqual(
                      fant_mean[0, 0].item(), y_at_low_x, delta=1
                  )
                  self.assertAlmostEqual(
                      fant_mean[0, 1].item(), 2 * y_at_low_x, delta=1
                  )
                  # delta=1 is a 1% error (since y_at_low_x = 100)
                  self.assertAlmostEqual(
                      fant_mean[1, 0].item(), y_at_high_x, delta=1
                  )
                  self.assertAlmostEqual(
                      fant_mean[1, 1].item(), 2 * y_at_high_x, delta=1
                  )
                  for i, fm_i in enumerate(fant.models):
                      n_points = 3 if decoupled else 4
                      self.assertEqual(
                          fm_i.train_inputs[0].shape,
                          torch.Size([20, n_points, 1]),
                      )
                      self.assertEqual(
                          fm_i.train_targets.shape,
                          torch.Size([20, n_points]),
                      )
                      if decoupled:
                          self.assertTrue(
                              torch.equal(
                                  fm_i.train_inputs[0][0][-1], X[1 - i]
                              )
                          )
  
imports: import itertools
  import warnings
  from copy import deepcopy
  from typing import Optional
  import torch
  from botorch.acquisition.objective import ScalarizedPosteriorTransform
  from botorch.exceptions.errors import BotorchTensorDimensionError
  from botorch.exceptions.warnings import OptimizationWarning
  from botorch.fit import fit_gpytorch_mll
  from botorch.models.gp_regression import SingleTaskGP
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.multitask import MultiTaskGP
  from botorch.models.transforms.input import Normalize
  from botorch.models.transforms.outcome import ChainedOutcomeTransform, Log, Standardize
  from botorch.posteriors import GPyTorchPosterior, PosteriorList, TransformedPosterior
  from botorch.sampling.base import MCSampler
  from botorch.sampling.list_sampler import ListSampler
  from botorch.sampling.normal import IIDNormalSampler
  from botorch.utils.testing import _get_random_data, BotorchTestCase
  from gpytorch.distributions import MultitaskMultivariateNormal, MultivariateNormal
  from gpytorch.kernels import MaternKernel, ScaleKernel
  from gpytorch.likelihoods import LikelihoodList
  from gpytorch.likelihoods.gaussian_likelihood import FixedNoiseGaussianLikelihood, GaussianLikelihood
  from gpytorch.means import ConstantMean
  from gpytorch.mlls import SumMarginalLogLikelihood
  from gpytorch.mlls.exact_marginal_log_likelihood import ExactMarginalLogLikelihood
  from gpytorch.priors import GammaPrior
  from torch import Tensor
label_desc: Use image node_id 9 for calling the TestModelListGP obj's underlying member method code with example usage: obj.test_fantasize_with_outcome_transform_fixed_noise() without return types