class_docstr: Batch Knowledge Gradient for multi-fidelity optimization.
  
  A version of `qKnowledgeGradient` that supports multi-fidelity optimization
  via a `CostAwareUtility` and the `project` and `expand` operators. If none
  of these are set, this acquisition function reduces to `qKnowledgeGradient`.
  Through `valfunc_cls` and `valfunc_argfac`, this can be changed into a custom
  multi-fidelity acquisition function (it is only KG if the terminal value is
  computed using a posterior mean).
class_docstr_tok: ["Batch","Knowledge","Gradient","for","multi-fidelity","optimization",".","A","version","of","`","qKnowledgeGradient","`","that","supports","multi-fidelity","optimization","via","a","`","CostAwareUtility","`","and","the","`","project","`","and","`","expand","`","operators",".","If","none","of","these","are","set",",","this","acquisition","function","reduces","to","`","qKnowledgeGradient","`",".","Through","`","valfunc_cls","`","and","`","valfunc_argfac","`",",","this","can","be","changed","into","a","custom","multi-fidelity","acquisition","function","(","it","is","only","KG","if","the","terminal","value","is","computed","using","a","posterior","mean",")","."]
code: def cost_sampler(self):
      if self._cost_sampler is None:
          # Note: Using the deepcopy here is essential. Removing this poses a
          # problem if the base model and the cost model have a different number
          # of outputs or test points (this would be caused by expand), as this
          # would trigger re-sampling the base samples in the fantasy sampler.
          # By cloning the sampler here, the right thing will happen if the
          # the sizes are compatible, if they are not this will result in
          # samples being drawn using different base samples, but it will at
          # least avoid changing state of the fantasy sampler.
          self._cost_sampler = deepcopy(self.sampler)
      return self._cost_sampler
  
imports: from __future__ import annotations
  from copy import deepcopy
  from typing import Any, Callable, Dict, Optional, Tuple, Type
  import torch
  from botorch import settings
  from botorch.acquisition.acquisition import AcquisitionFunction, MCSamplerMixin, OneShotAcquisitionFunction
  from botorch.acquisition.analytic import PosteriorMean
  from botorch.acquisition.cost_aware import CostAwareUtility
  from botorch.acquisition.monte_carlo import MCAcquisitionFunction, qSimpleRegret
  from botorch.acquisition.objective import MCAcquisitionObjective, PosteriorTransform
  from botorch.exceptions.errors import UnsupportedError
  from botorch.models.model import Model
  from botorch.sampling.base import MCSampler
  from botorch.sampling.normal import SobolQMCNormalSampler
  from botorch.utils.transforms import concatenate_pending_points, match_batch_shape, t_batch_mode_transform
  from torch import Tensor
label_desc: Use image node_id 2 for calling the qMultiFidelityKnowledgeGradient obj's underlying member method code with example usage: obj.cost_sampler() and returns: self