code: def test_KnowledgeGradient_multifidelity(self) -> None:
      search_space_digest = SearchSpaceDigest(
          feature_names=self.feature_names,
          bounds=self.bounds,
          fidelity_features=[2],
          target_values={2: 5.0},
      )
      model = KnowledgeGradient()
      model.fit(
          datasets=[self.dataset],
          metric_names=["L2NormMetric"],
          search_space_digest=search_space_digest,
      )
  
      torch_opt_config = TorchOptConfig(
          objective_weights=self.objective_weights,
          model_gen_options={
              "acquisition_function_kwargs": self.acq_options,
              "optimizer_kwargs": self.optimizer_options,
          },
      )
      # Check best point selection within bounds (some numerical tolerance)
      xbest = model.best_point(
          search_space_digest=search_space_digest,
          torch_opt_config=torch_opt_config,
      )
      lb = torch.tensor([b[0] for b in self.bounds]) - 1e-5
      ub = torch.tensor([b[1] for b in self.bounds]) + 1e-5
      self.assertTrue(torch.all(xbest <= ub))
      self.assertTrue(torch.all(xbest >= lb))
  
      # check error when no target fidelities are specified
      with self.assertRaises(RuntimeError):
          model.best_point(
              search_space_digest=dataclasses.replace(
                  search_space_digest,
                  target_values={},
              ),
              torch_opt_config=torch_opt_config,
          )
  
      # check generation
      n = 2
      X_dummy = torch.zeros(1, n, 3, **self.tkwargs)
      acq_dummy = torch.tensor(0.0, **self.tkwargs)
      dummy = (X_dummy, acq_dummy)
      with mock.patch(
          self.optimize_acqf, side_effect=[dummy]
      ) as mock_optimize_acqf:
          gen_results = model.gen(
              n=n,
              search_space_digest=search_space_digest,
              torch_opt_config=torch_opt_config,
          )
          self.assertTrue(
              torch.equal(gen_results.points, X_dummy.cpu())
          )
          self.assertTrue(
              torch.equal(
                  gen_results.weights,
                  torch.ones(n, dtype=self.tkwargs["dtype"]),
              )
          )
          mock_optimize_acqf.assert_called()  # called twice, once for best_point
  
      # test error message
      with self.assertRaises(UnsupportedError):
          xbest = model.best_point(
              search_space_digest=search_space_digest,
              torch_opt_config=dataclasses.replace(
                  torch_opt_config,
                  linear_constraints=(
                      torch.tensor([[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]]),
                      torch.tensor([[0.5], [1.0]]),
                  ),
              ),
          )
  
      # test input warping
      self.assertFalse(model.use_input_warping)
      model = KnowledgeGradient(use_input_warping=True)
      model.fit(
          datasets=[self.dataset],
          metric_names=["L2NormMetric"],
          search_space_digest=search_space_digest,
      )
      self.assertTrue(model.use_input_warping)
      self.assertTrue(hasattr(model.model, "input_transform"))
      self.assertIsInstance(model.model.input_transform, Warp)
  
      # test loocv pseudo likelihood
      self.assertFalse(model.use_loocv_pseudo_likelihood)
      model = KnowledgeGradient(use_loocv_pseudo_likelihood=True)
      model.fit(
          datasets=[self.dataset],
          metric_names=["L2NormMetric"],
          search_space_digest=search_space_digest,
      )
      self.assertTrue(model.use_loocv_pseudo_likelihood)
  
imports: import dataclasses
  from typing import Any, Dict
  from unittest import mock
  import torch
  from ax.core.search_space import SearchSpaceDigest
  from ax.models.torch.botorch_kg import _instantiate_KG, KnowledgeGradient
  from ax.models.torch_base import TorchOptConfig
  from ax.utils.common.testutils import TestCase
  from ax.utils.testing.mock import fast_botorch_optimize
  from botorch.acquisition.analytic import PosteriorMean
  from botorch.acquisition.fixed_feature import FixedFeatureAcquisitionFunction
  from botorch.acquisition.knowledge_gradient import qMultiFidelityKnowledgeGradient
  from botorch.acquisition.monte_carlo import qSimpleRegret
  from botorch.acquisition.objective import LinearMCObjective, ScalarizedPosteriorTransform
  from botorch.exceptions.errors import UnsupportedError
  from botorch.models.transforms.input import Warp
  from botorch.sampling.normal import IIDNormalSampler, SobolQMCNormalSampler
  from botorch.utils.datasets import SupervisedDataset
label_desc: Use image node_id 3 for calling the KnowledgeGradientTest obj's underlying member method code with example usage: obj.test_KnowledgeGradient_multifidelity() without return types