class_docstr: Batch Hypervolume Knowledge Gradient using one-shot optimization.
  
  The hypervolume knowledge gradient seeks to maximize the difference in
  hypervolume of the hypervolume-maximizing set of a fixed size after
  conditioning the unknown observation(s) that would be recevied if X where
  evalauted. See [Daulton2023hvkg]_ for details.
  
  This computes the batch Hypervolume Knowledge Gradient using fantasies for
  the outer expectation and 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 (Note this is
  `N x N_pareto` optimal designs). For a fixed number of fantasies, all points
  in `X` can be optimized in a "one-shot" fashion.
class_docstr_tok: ["Batch","Hypervolume","Knowledge","Gradient","using","one-shot","optimization",".","The","hypervolume","knowledge","gradient","seeks","to","maximize","the","difference","in","hypervolume","of","the","hypervolume-maximizing","set","of","a","fixed","size","after","conditioning","the","unknown","observation","(","s",")","that","would","be","recevied","if","X","where","evalauted",".","See","[","Daulton2023hvkg","]","_","for","details",".","This","computes","the","batch","Hypervolume","Knowledge","Gradient","using","fantasies","for","the","outer","expectation","and","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","(","Note","this","is","`","N","x","N_pareto","`","optimal","designs",")",".","For","a","fixed","number","of","fantasies",",","all","points","in","`","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_hvkg_fantasy_points(
          X=X, n_f=self.num_fantasies, num_pareto=self.num_pareto
      )
      q = X_actual.shape[-2]
  
      # construct evaluation_mask
      evaluation_mask = self.construct_evaluation_mask(X=X_actual)
      # 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`
      # Note: For the decoupled, cost-aware (e.g. not async) setting, we
      # technically want to make sure to copy the base samples here, so
      # that the same fantasies are used for X_pending on the left and
      # right of the KG terms.
      fantasy_model = self.model.fantasize(
          X=X_actual,
          sampler=self.sampler,
          evaluation_mask=evaluation_mask,
      )
  
      # get the value function
      value_function = _get_hv_value_function(
          model=fantasy_model,
          ref_point=self.ref_point,
          objective=self.objective,
          sampler=self.inner_sampler,
          use_posterior_mean=self.use_posterior_mean,
      )
  
      # make sure to propagate gradients to the fantasy model train inputs
      with settings.propagate_grads(True):
          # X_fantasies is num_pseudo_points x batch_shape x 1 x d
          # Reshape it into num_fantasies x batch_shape x num_pareto x d
          shape = torch.Size(
              [
                  self.num_fantasies,
                  *X_fantasies.shape[1:-2],
                  self.num_pareto,
                  X_fantasies.shape[-1],
              ]
          )
          values = value_function(
              X=X_fantasies.reshape(shape)
          )  # num_fantasies x b
  
      if self.current_value is not None:
          values = values - self.current_value
  
      if self.cost_aware_utility is not None:
          values = self.cost_aware_utility(
              # exclude pending points
              X=X_actual[..., :q, :],
              # cost-weighting relies on nonnegative deltas
              deltas=values.clamp_min(0.0),
              sampler=self.cost_sampler,
              X_evaluation_mask=self.X_evaluation_mask,
          )
  
      # return average over the fantasy samples
      return values.mean(dim=0)
  
imports: from copy import deepcopy
  from typing import Any, Callable, Dict, List, Optional, Tuple, Type
  import torch
  from botorch import settings
  from botorch.acquisition.acquisition import AcquisitionFunction, OneShotAcquisitionFunction
  from botorch.acquisition.cost_aware import CostAwareUtility
  from botorch.acquisition.decoupled import DecoupledAcquisitionFunction
  from botorch.acquisition.knowledge_gradient import ProjectedAcquisitionFunction
  from botorch.acquisition.multi_objective.monte_carlo import MultiObjectiveMCAcquisitionFunction, qExpectedHypervolumeImprovement
  from botorch.acquisition.multi_objective.objective import MCMultiOutputObjective
  from botorch.exceptions.errors import UnsupportedError
  from botorch.models.deterministic import PosteriorMeanModel
  from botorch.models.model import Model
  from botorch.sampling.base import MCSampler
  from botorch.sampling.list_sampler import ListSampler
  from botorch.sampling.normal import SobolQMCNormalSampler
  from botorch.sampling.stochastic_samplers import StochasticSampler
  from botorch.utils.multi_objective.box_decompositions.non_dominated import FastNondominatedPartitioning
  from botorch.utils.transforms import match_batch_shape, t_batch_mode_transform
  from torch import Tensor
label_desc: Use image node_id 3 for calling the qHypervolumeKnowledgeGradient obj's underlying member method code with example usage: obj.forward(X) and returns: values