class_docstr: Abstract base class for all Variational Strategies.
docstr: Performs the online variational conditioning (OVC) strategy of Maddox et al, '21 to return
  an exact GP model that incorporates the inputs and targets alongside the variational model's inducing
  points and targets.
  
  Currently, instead of directly updating the variational parameters (and inducing points), we instead
  return an ExactGP model rather than an updated variational GP model. This is done primarily for
  numerical stability.
  
  Unlike the ExactGP's call for get_fantasy_model, we enable options for mean_module and covar_module
  that allow specification of the mean / covariance. We expect that either the mean and covariance
  modules are attributes of the model itself called mean_module and covar_module respectively OR that you
  pass them into this method explicitly.
  
  :param inputs: (`b1 x ... x bk x m x d` or `f x b1 x ... x bk x m x d`) Locations of fantasy
      observations.
  :param targets: (`b1 x ... x bk x m` or `f x b1 x ... x bk x m`) Labels of fantasy observations.
  :param mean_module: torch module describing the mean function of the GP model. Optional if
      `mean_module` is already an attribute of the variational GP.
  :param covar_module: torch module describing the covariance function of the GP model. Optional
      if `covar_module` is already an attribute of the variational GP.
  :return: An `ExactGP` model with `k + m` training examples, where the `m` fantasy examples have been added
      and all test-time caches have been updated. We assume that there are `k` inducing points in this variational
      GP. Note that we return an `ExactGP` rather than a variational GP.
  
  Reference: "Conditioning Sparse Variational Gaussian Processes for Online Decision-Making,"
      Maddox, Stanton, Wilson, NeurIPS, '21
      https://papers.nips.cc/paper/2021/hash/325eaeac5bef34937cfdc1bd73034d17-Abstract.html
code: def get_fantasy_model(
      self,
      inputs: Tensor,
      targets: Tensor,
      mean_module: Optional[Module] = None,
      covar_module: Optional[Module] = None,
      **kwargs,
  ) -> ExactGP:
      r"""
      Performs the online variational conditioning (OVC) strategy of Maddox et al, '21 to return
      an exact GP model that incorporates the inputs and targets alongside the variational model's inducing
      points and targets.
  
      Currently, instead of directly updating the variational parameters (and inducing points), we instead
      return an ExactGP model rather than an updated variational GP model. This is done primarily for
      numerical stability.
  
      Unlike the ExactGP's call for get_fantasy_model, we enable options for mean_module and covar_module
      that allow specification of the mean / covariance. We expect that either the mean and covariance
      modules are attributes of the model itself called mean_module and covar_module respectively OR that you
      pass them into this method explicitly.
  
      :param inputs: (`b1 x ... x bk x m x d` or `f x b1 x ... x bk x m x d`) Locations of fantasy
          observations.
      :param targets: (`b1 x ... x bk x m` or `f x b1 x ... x bk x m`) Labels of fantasy observations.
      :param mean_module: torch module describing the mean function of the GP model. Optional if
          `mean_module` is already an attribute of the variational GP.
      :param covar_module: torch module describing the covariance function of the GP model. Optional
          if `covar_module` is already an attribute of the variational GP.
      :return: An `ExactGP` model with `k + m` training examples, where the `m` fantasy examples have been added
          and all test-time caches have been updated. We assume that there are `k` inducing points in this variational
          GP. Note that we return an `ExactGP` rather than a variational GP.
  
      Reference: "Conditioning Sparse Variational Gaussian Processes for Online Decision-Making,"
          Maddox, Stanton, Wilson, NeurIPS, '21
          https://papers.nips.cc/paper/2021/hash/325eaeac5bef34937cfdc1bd73034d17-Abstract.html
      """
  
      # currently, we only support fantasization for CholeskyVariationalDistribution and
      # whitened / unwhitened variational strategies
      if not self.has_fantasy_strategy:
          raise NotImplementedError(
              f"No fantasy model support for {self.__class__.__name__}. "
              "Only VariationalStrategy and UnwhitenedVariationalStrategy are currently supported."
          )
      else:
          from . import (
              CholeskyVariationalDistribution,
          )  # Circular import otherwise
  
          if not isinstance(
              self._variational_distribution,
              CholeskyVariationalDistribution,
          ):
              raise NotImplementedError(
                  "Fantasy models are only support for variational models with CholeskyVariationalDistribution."
              )
  
      if not isinstance(self.model.likelihood, GaussianLikelihood):
          raise NotImplementedError(
              f"No fantasy model support for {self.model.likelihood.__class__.__name__}. "
              "Only GaussianLikelihoods are currently supported."
          )
      # we assume that either the user has given the model a mean_module and a covar_module
      # or that it will be passed into the get_fantasy_model function. we check for these.
      if mean_module is None:
          mean_module = getattr(self.model, "mean_module", None)
          if mean_module is None:
              raise ModuleNotFoundError(
                  "Either you must provide a mean_module as input to get_fantasy_model "
                  "or it must be an attribute of the model called mean_module."
              )
      if covar_module is None:
          covar_module = getattr(self.model, "covar_module", None)
          if covar_module is None:
              # raise an error
              raise ModuleNotFoundError(
                  "Either you must provide a covar_module as input to get_fantasy_model "
                  "or it must be an attribute of the model called covar_module."
              )
  
      # first we construct an exact model over the inducing points with the inducing covariance
      # matrix
      inducing_exact_model = self.amortized_exact_gp(
          mean_module=mean_module, covar_module=covar_module
      )
  
      # then we update this model by adding in the inputs and pseudo targets
      # finally we fantasize wrt targets
      fantasy_model = inducing_exact_model.get_fantasy_model(
          inputs, targets, **kwargs
      )
      fant_pred_strat = fantasy_model.prediction_strategy
  
      # first we update the lik_train_train_covar
      # do the mean cache again because the mean cache resets the likelihood forward
      train_mean = fantasy_model.mean_module(
          *fantasy_model.train_inputs
      )
      train_labels_offset = (
          fant_pred_strat.train_labels - train_mean
      ).unsqueeze(-1)
      fantasy_lik_train_root_inv = (
          fant_pred_strat.lik_train_train_covar.root_inv_decomposition()
      )
      mean_cache = fantasy_lik_train_root_inv.matmul(
          train_labels_offset
      ).squeeze(-1)
      mean_cache = _add_cache_hook(mean_cache, fant_pred_strat)
      add_to_cache(fant_pred_strat, "mean_cache", mean_cache)
      # TODO: should we update the covar_cache?
  
      fantasy_model.prediction_strategy = fant_pred_strat
      return fantasy_model
  
imports: import functools
  from abc import ABC, abstractproperty
  from copy import deepcopy
  from typing import Optional, Tuple, Union
  import torch
  from linear_operator.operators import LinearOperator
  from torch import Tensor
  from ..None import settings
  from ..distributions import Delta, Distribution, MultivariateNormal
  from ..kernels import Kernel
  from ..likelihoods import GaussianLikelihood
  from ..means import Mean
  from ..models import ApproximateGP, ExactGP
  from ..models.exact_prediction_strategies import DefaultPredictionStrategy
  from ..module import Module
  from ..utils.memoize import add_to_cache, cached, clear_cache_hook
  from .None import _VariationalDistribution
label_desc: Use image node_id 12 for calling the _VariationalStrategy obj's underlying member method code with example usage: obj.get_fantasy_model(inputs, targets, mean_module, covar_module) and returns: fantasy_model