class_docstr: Multi-fidelity acquisition function for General-purpose Information-Based
  Bayesian optimization (GIBBON).
  
  The acquisition function for multi-fidelity max-value entropy search
  with support for trace observations. See [Takeno2020mfmves]_
  for a detailed discussion of the basic ideas on multi-fidelity MES
  (note that this implementation is somewhat different). This acquisition function
  is similar to `qMultiFidelityMaxValueEntropy` but computes the information gain
  from the lower bound described in [Moss2021gibbon].
  
  The model must be single-outcome, unless using a PosteriorTransform.
  The batch case `q > 1` is supported through cyclic optimization and fantasies.
  
  Example:
      >>> model = SingleTaskGP(train_X, train_Y)
      >>> candidate_set = torch.rand(1000, bounds.size(1))
      >>> candidate_set = bounds[0] + (bounds[1] - bounds[0]) * candidate_set
      >>> MF_qGIBBON = qMultiFidelityLowerBoundMaxValueEntropy(model, candidate_set)
      >>> mf_gibbon = MF_qGIBBON(test_X)
docstr: Compute GIBBON's approximation of information gain at the design points `X`.
  
  When using GIBBON for batch optimization (i.e `q > 1`), we calculate the
  additional information provided by adding a new candidate point to the current
  batch of design points (`X_pending`), rather than calculating the information
  provided by the whole batch. This allows a modest computational saving.
  
  Args:
      X: A `batch_shape x 1 x d`-dim Tensor of `batch_shape` t-batches
          with `1` `d`-dim design point each.
      mean_M: A `batch_shape x 1`-dim Tensor of means.
      variance_M: A `batch_shape x 1`-dim Tensor of variances
          consisting of `batch_shape` t-batches with `num_fantasies` fantasies.
      covar_mM: A `batch_shape x num_fantasies x (1 + num_trace_observations)`
          -dim Tensor of covariances.
  
  Returns:
      A `num_fantasies x batch_shape`-dim Tensor of information gains at the
      given design points `X`.
docstr_tok: ["Compute","GIBBON","'s","approximation","of","information","gain","at","the","design","points","`","X","`",".","When","using","GIBBON","for","batch","optimization","(","i.e","`","q",">","1","`",")",",","we","calculate","the","additional","information","provided","by","adding","a","new","candidate","point","to","the","current","batch","of","design","points","(","`","X_pending","`",")",",","rather","than","calculating","the","information","provided","by","the","whole","batch",".","This","allows","a","modest","computational","saving",".","Args",":","X",":","A","`","batch_shape","x","1","x","d","`","-dim","Tensor","of","`","batch_shape","`","t-batches","with","`","1","`","`","d","`","-dim","design","point","each",".","mean_M",":","A","`","batch_shape","x","1","`","-dim","Tensor","of","means",".","variance_M",":","A","`","batch_shape","x","1","`","-dim","Tensor","of","variances","consisting","of","`","batch_shape","`","t-batches","with","`","num_fantasies","`","fantasies",".","covar_mM",":","A","`","batch_shape","x","num_fantasies","x","(","1","+","num_trace_observations",")","`","-dim","Tensor","of","covariances",".","Returns",":","A","`","num_fantasies","x","batch_shape","`","-dim","Tensor","of","information","gains","at","the","given","design","points","`","X","`","."]
code: def _compute_information_gain(
      self,
      X: Tensor,
      mean_M: Tensor,
      variance_M: Tensor,
      covar_mM: Tensor,
  ) -> Tensor:
      r"""Compute GIBBON's approximation of information gain at the design points `X`.
  
      When using GIBBON for batch optimization (i.e `q > 1`), we calculate the
      additional information provided by adding a new candidate point to the current
      batch of design points (`X_pending`), rather than calculating the information
      provided by the whole batch. This allows a modest computational saving.
  
      Args:
          X: A `batch_shape x 1 x d`-dim Tensor of `batch_shape` t-batches
              with `1` `d`-dim design point each.
          mean_M: A `batch_shape x 1`-dim Tensor of means.
          variance_M: A `batch_shape x 1`-dim Tensor of variances
              consisting of `batch_shape` t-batches with `num_fantasies` fantasies.
          covar_mM: A `batch_shape x num_fantasies x (1 + num_trace_observations)`
              -dim Tensor of covariances.
  
      Returns:
          A `num_fantasies x batch_shape`-dim Tensor of information gains at the
          given design points `X`.
      """
      return qLowerBoundMaxValueEntropy._compute_information_gain(
          self,
          X=X,
          mean_M=mean_M,
          variance_M=variance_M,
          covar_mM=covar_mM,
      )
  
imports: from __future__ import annotations
  from abc import ABC, abstractmethod
  from copy import deepcopy
  from math import log
  from typing import Any, Callable, Optional
  import numpy
  import torch
  from botorch.acquisition.acquisition import AcquisitionFunction, MCSamplerMixin
  from botorch.acquisition.cost_aware import CostAwareUtility, InverseCostWeightedUtility
  from botorch.acquisition.objective import PosteriorTransform
  from botorch.exceptions.errors import UnsupportedError
  from botorch.models.cost import AffineFidelityCostModel
  from botorch.models.model import Model
  from botorch.models.utils import check_no_nans
  from botorch.sampling.normal import SobolQMCNormalSampler
  from botorch.utils.transforms import match_batch_shape, t_batch_mode_transform
  from linear_operator.functions import inv_quad
  from linear_operator.utils.cholesky import psd_safe_cholesky
  from scipy.optimize import brentq
  from scipy.stats import norm
  from torch import Tensor
label_desc: Use image node_id 1 for calling the qMultiFidelityLowerBoundMaxValueEntropy obj's underlying member method code with example usage: obj._compute_information_gain(X, mean_M, variance_M, covar_mM) and returns: qLowerBoundMaxValueEntropy