class_docstr: Similar to :obj:`~gpytorch.variational.VariationalStrategy`, but does not perform the
  whitening operation. In almost all cases :obj:`~gpytorch.variational.VariationalStrategy`
  is preferable, with a few exceptions:
  
  - When the inducing points are exactly equal to the training points (i.e. :math:`\mathbf Z = \mathbf X`).
    Unwhitened models are faster in this case.
  
  - When the number of inducing points is very large (e.g. >2000). Unwhitened models can use CG for faster
    computation.
  
  :param ~model: Model this strategy is applied to.
      Typically passed in when the VariationalStrategy is created in the
      __init__ method of the user defined model.
  :param inducing_points: Tensor containing a set of inducing
      points to use for variational inference.
  :param variational_distribution: A
      VariationalDistribution object that represents the form of the variational distribution :math:`q(\mathbf u)`
  :param learn_inducing_locations: (default True): Whether or not
      the inducing point locations :math:`\mathbf Z` should be learned (i.e. are they
      parameters of the model).
  :param jitter_val: Amount of diagonal jitter to add for Cholesky factorization numerical stability
class_docstr_tok: ["Similar","to",":","obj",":","`","~gpytorch.variational.VariationalStrategy","`",",","but","does","not","perform","the","whitening","operation",".","In","almost","all","cases",":","obj",":","`","~gpytorch.variational.VariationalStrategy","`","is","preferable",",","with","a","few","exceptions",":","-","When","the","inducing","points","are","exactly","equal","to","the","training","points","(","i.e",".",":","math",":","`","\\mathbf","Z","=","\\mathbf","X","`",")",".","Unwhitened","models","are","faster","in","this","case",".","-","When","the","number","of","inducing","points","is","very","large","(","e.g",".",">","2000",")",".","Unwhitened","models","can","use","CG","for","faster","computation",".",":","param","~model",":","Model","this","strategy","is","applied","to",".","Typically","passed","in","when","the","VariationalStrategy","is","created","in","the","__init__","method","of","the","user","defined","model",".",":","param","inducing_points",":","Tensor","containing","a","set","of","inducing","points","to","use","for","variational","inference",".",":","param","variational_distribution",":","A","VariationalDistribution","object","that","represents","the","form","of","the","variational","distribution",":","math",":","`","q","(","\\mathbf","u",")","`",":","param","learn_inducing_locations",":","(","default","True",")",":","Whether","or","not","the","inducing","point","locations",":","math",":","`","\\mathbf","Z","`","should","be","learned","(","i.e",".","are","they","parameters","of","the","model",")",".",":","param","jitter_val",":","Amount","of","diagonal","jitter","to","add","for","Cholesky","factorization","numerical","stability"]
code: def pseudo_points(self) -> Tuple[Tensor, Tensor]:
      # TODO: implement for other distributions
      # retrieve the variational mean, m and covariance matrix, S.
      if not isinstance(
          self._variational_distribution,
          CholeskyVariationalDistribution,
      ):
          raise NotImplementedError(
              "Only CholeskyVariationalDistribution has pseudo-point support currently, ",
              "but your _variational_distribution is a ",
              self._variational_distribution.__name__,
          )
  
      # retrieve the variational mean, m and covariance matrix, S.
      var_cov_root = TriangularLinearOperator(
          self._variational_distribution.chol_variational_covar
      )
      var_cov = CholLinearOperator(var_cov_root)
      var_mean = self.variational_distribution.mean  # .unsqueeze(-1)
      if var_mean.shape[-1] != 1:
          var_mean = var_mean.unsqueeze(-1)
  
      # R = K - S
      Kmm = self.model.covar_module(self.inducing_points)
      res = Kmm - var_cov
  
      cov_diff = res
  
      # D_a = (S^{-1} - K^{-1})^{-1} = S + S R^{-1} S
      # note that in the whitened case R = I - S, unwhitened R = K - S
      # we compute (R R^{T})^{-1} R^T S for stability reasons as R is probably not PSD.
      eval_lhs = var_cov.to_dense()
      eval_rhs = cov_diff.transpose(-1, -2).matmul(eval_lhs)
      inner_term = cov_diff.matmul(cov_diff.transpose(-1, -2))
      # TODO: flag the jitter here
      inner_solve = inner_term.add_jitter(self.jitter_val).solve(
          eval_rhs, eval_lhs.transpose(-1, -2)
      )
      inducing_covar = var_cov + inner_solve
  
      # mean term: D_a S^{-1} m
      # unwhitened: (S - S R^{-1} S) S^{-1} m = (I - S R^{-1}) m
      rhs = cov_diff.transpose(-1, -2).matmul(var_mean)
      inner_rhs_mean_solve = inner_term.add_jitter(
          self.jitter_val
      ).solve(rhs)
      pseudo_target_mean = var_mean + var_cov.matmul(
          inner_rhs_mean_solve
      )
  
      # ensure inducing covar is psd
      try:
          pseudo_target_covar = CholLinearOperator(
              inducing_covar.add_jitter(self.jitter_val).cholesky()
          ).to_dense()
      except NotPSDError:
          from linear_operator.operators import DiagLinearOperator
  
          evals, evecs = torch.linalg.eigh(inducing_covar)
          pseudo_target_covar = (
              evecs.matmul(DiagLinearOperator(evals + self.jitter_val))
              .matmul(evecs.transpose(-1, -2))
              .to_dense()
          )
  
      return pseudo_target_covar, pseudo_target_mean
  
file_path: gpytorch/gpytorch/variational/unwhitened_variational_strategy.py
imports: import math
  from typing import Optional, Tuple
  import torch
  from linear_operator import to_dense
  from linear_operator.operators import CholLinearOperator, DiagLinearOperator, LinearOperator, PsdSumLinearOperator, RootLinearOperator, TriangularLinearOperator, ZeroLinearOperator
  from linear_operator.utils.cholesky import psd_safe_cholesky
  from linear_operator.utils.errors import NotPSDError
  from torch import Tensor
  from ..None import settings
  from ..distributions import MultivariateNormal
  from ..utils.memoize import add_to_cache, cached
  from ._variational_strategy import _VariationalStrategy
  from .cholesky_variational_distribution import CholeskyVariationalDistribution
label_desc: Use image node_id 3 for calling the UnwhitenedVariationalStrategy obj's underlying member method code with example usage: obj.pseudo_points() and returns: pseudo_target_covar,  pseudo_target_mean