class_docstr: Batch Knowledge Gradient using one-shot optimization.
  
  This computes the batch Knowledge Gradient using fantasies for the outer
  expectation and either the model posterior mean or MC-sampling for the inner
  expectation.
  
  In addition to the design variables, the input `X` also includes variables
  for the optimal designs for each of the fantasy models. For a fixed number
  of fantasies, all parts of `X` can be optimized in a "one-shot" fashion.
class_docstr_tok: ["Batch","Knowledge","Gradient","using","one-shot","optimization",".","This","computes","the","batch","Knowledge","Gradient","using","fantasies","for","the","outer","expectation","and","either","the","model","posterior","mean","or","MC-sampling","for","the","inner","expectation",".","In","addition","to","the","design","variables",",","the","input","`","X","`","also","includes","variables","for","the","optimal","designs","for","each","of","the","fantasy","models",".","For","a","fixed","number","of","fantasies",",","all","parts","of","`","X","`","can","be","optimized","in","a","``","one-shot","''","fashion","."]
docstr: Evaluate qKnowledgeGradient on the candidate set `X`.
  
  Args:
      X: A `b x (q + num_fantasies) x d` Tensor with `b` t-batches of
          `q + num_fantasies` design points each. We split this X tensor
          into two parts in the `q` dimension (`dim=-2`). The first `q`
          are the q-batch of design points and the last num_fantasies are
          the current solutions of the inner optimization problem.
  
          `X_fantasies = X[..., -num_fantasies:, :]`
          `X_fantasies.shape = b x num_fantasies x d`
  
          `X_actual = X[..., :-num_fantasies, :]`
          `X_actual.shape = b x q x d`
  
  Returns:
      A Tensor of shape `b`. For t-batch b, the q-KG value of the design
          `X_actual[b]` is averaged across the fantasy models, where
          `X_fantasies[b, i]` is chosen as the final selection for the
          `i`-th fantasy model.
          NOTE: If `current_value` is not provided, then this is not the
          true KG value of `X_actual[b]`, and `X_fantasies[b, : ]` must be
          maximized at fixed `X_actual[b]`.
docstr_tok: ["Evaluate","qKnowledgeGradient","on","the","candidate","set","`","X","`",".","Args",":","X",":","A","`","b","x","(","q","+","num_fantasies",")","x","d","`","Tensor","with","`","b","`","t-batches","of","`","q","+","num_fantasies","`","design","points","each",".","We","split","this","X","tensor","into","two","parts","in","the","`","q","`","dimension","(","`","dim=-2","`",")",".","The","first","`","q","`","are","the","q-batch","of","design","points","and","the","last","num_fantasies","are","the","current","solutions","of","the","inner","optimization","problem",".","`","X_fantasies","=","X","[","...",",","-num_fantasies",":",",",":","]","`","`","X_fantasies.shape","=","b","x","num_fantasies","x","d","`","`","X_actual","=","X","[","...",",",":","-num_fantasies",",",":","]","`","`","X_actual.shape","=","b","x","q","x","d","`","Returns",":","A","Tensor","of","shape","`","b","`",".","For","t-batch","b",",","the","q-KG","value","of","the","design","`","X_actual","[","b","]","`","is","averaged","across","the","fantasy","models",",","where","`","X_fantasies","[","b",",","i","]","`","is","chosen","as","the","final","selection","for","the","`","i","`","-th","fantasy","model",".","NOTE",":","If","`","current_value","`","is","not","provided",",","then","this","is","not","the","true","KG","value","of","`","X_actual","[","b","]","`",",","and","`","X_fantasies","[","b",",",":","]","`","must","be","maximized","at","fixed","`","X_actual","[","b","]","`","."]
code: def forward(self, X: Tensor) -> Tensor:
      r"""Evaluate qKnowledgeGradient on the candidate set `X`.
  
      Args:
          X: A `b x (q + num_fantasies) x d` Tensor with `b` t-batches of
              `q + num_fantasies` design points each. We split this X tensor
              into two parts in the `q` dimension (`dim=-2`). The first `q`
              are the q-batch of design points and the last num_fantasies are
              the current solutions of the inner optimization problem.
  
              `X_fantasies = X[..., -num_fantasies:, :]`
              `X_fantasies.shape = b x num_fantasies x d`
  
              `X_actual = X[..., :-num_fantasies, :]`
              `X_actual.shape = b x q x d`
  
      Returns:
          A Tensor of shape `b`. For t-batch b, the q-KG value of the design
              `X_actual[b]` is averaged across the fantasy models, where
              `X_fantasies[b, i]` is chosen as the final selection for the
              `i`-th fantasy model.
              NOTE: If `current_value` is not provided, then this is not the
              true KG value of `X_actual[b]`, and `X_fantasies[b, : ]` must be
              maximized at fixed `X_actual[b]`.
      """
      X_actual, X_fantasies = _split_fantasy_points(
          X=X, n_f=self.num_fantasies
      )
  
      # We only concatenate X_pending into the X part after splitting
      if self.X_pending is not None:
          X_actual = torch.cat(
              [X_actual, match_batch_shape(self.X_pending, X_actual)],
              dim=-2,
          )
  
      # construct the fantasy model of shape `num_fantasies x b`
      fantasy_model = self.model.fantasize(
          X=X_actual,
          sampler=self.sampler,
      )
  
      # get the value function
      value_function = _get_value_function(
          model=fantasy_model,
          objective=self.objective,
          posterior_transform=self.posterior_transform,
          sampler=self.inner_sampler,
      )
  
      # make sure to propagate gradients to the fantasy model train inputs
      with settings.propagate_grads(True):
          values = value_function(X=X_fantasies)  # num_fantasies x b
  
      if self.current_value is not None:
          values = values - self.current_value
  
      # return average over the fantasy samples
      return values.mean(dim=0)
  
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 qKnowledgeGradient obj's underlying member method code with example usage: obj.forward(X) and returns: values