class_docstr: A PSDKernel which computes the variational kernel from [Titsias, 2009].
  
  The VariationalGaussianProcess can be cast as a special case of
  GaussianProcess with a particular class of kernel function. The idea is that
  instead of conditioning exactly on data, which would cost us time cubic in the
  number of data points, we learn a variational posterior over function values
  at a set of so-called "inducing points" and then make predictions by
  marginalizing over the variational posterior over the function values at the
  inducing point locations. This yields a new model, which is again just a GP
  but with a more complicated kernel function than we started with (similar to
  the way in which an exact GP posterior is just another GP with a more
  complicated kernel function).
  
  Having established that context, we can describe the `_VariationalKernel`. It
  is parameterized by
    - a `base_kernel` (another PSDKernel instance), the kernel we use to model
      the covariance structure of our true GP model,
    - `inducing_index_points`, the locations of the inducing points in the index
      set,
    - `variational_scale`, the scale matrix of the (multivariate Normal)
      variational posterior in the approximate model, that is, the scale matrix
      of the variational distribution `q(f(z)) ~= p(f(z) | f(z))`, where `z` are
      the inducing point locations, `x` the observation locations, and `f(.)`
      the function values at those locations.
  
  More precisely, it computes its value on inputs `x`, `y` as follows where, for
  brevity,
  
    - `z` are the aforementioned `inducing_index_points`
    - `var_scale` is the variational scale matrix
    - `k0` is the function represented by `base_kernel`
    - `k` is an the function represented by this class
  
  ```none
    kxy = k0(x, y)
    kxz = k0(x, z)
    kzy = k0(z, y)
    kzz = k0(z, z)
    k(x, y) = (kxy -
               kxz @ inv(kzz) @ kzy +
               kxz @ inv(kzz) @ var_scale @ var_scale^T @ inv(kzz) @ kzy)
  ```
class_docstr_tok: ["A","PSDKernel","which","computes","the","variational","kernel","from","[","Titsias",",","2009","]",".","The","VariationalGaussianProcess","can","be","cast","as","a","special","case","of","GaussianProcess","with","a","particular","class","of","kernel","function",".","The","idea","is","that","instead","of","conditioning","exactly","on","data",",","which","would","cost","us","time","cubic","in","the","number","of","data","points",",","we","learn","a","variational","posterior","over","function","values","at","a","set","of","so-called","``","inducing","points","''","and","then","make","predictions","by","marginalizing","over","the","variational","posterior","over","the","function","values","at","the","inducing","point","locations",".","This","yields","a","new","model",",","which","is","again","just","a","GP","but","with","a","more","complicated","kernel","function","than","we","started","with","(","similar","to","the","way","in","which","an","exact","GP","posterior","is","just","another","GP","with","a","more","complicated","kernel","function",")",".","Having","established","that","context",",","we","can","describe","the","`","_VariationalKernel","`",".","It","is","parameterized","by","-","a","`","base_kernel","`","(","another","PSDKernel","instance",")",",","the","kernel","we","use","to","model","the","covariance","structure","of","our","true","GP","model",",","-","`","inducing_index_points","`",",","the","locations","of","the","inducing","points","in","the","index","set",",","-","`","variational_scale","`",",","the","scale","matrix","of","the","(","multivariate","Normal",")","variational","posterior","in","the","approximate","model",",","that","is",",","the","scale","matrix","of","the","variational","distribution","`","q","(","f","(","z",")",")","~=","p","(","f","(","z",")","|","f","(","z",")",")","`",",","where","`","z","`","are","the","inducing","point","locations",",","`","x","`","the","observation","locations",",","and","`","f","(",".",")","`","the","function","values","at","those","locations",".","More","precisely",",","it","computes","its","value","on","inputs","`","x","`",",","`","y","`","as","follows","where",",","for","brevity",",","-","`","z","`","are","the","aforementioned","`","inducing_index_points","`","-","`","var_scale","`","is","the","variational","scale","matrix","-","`","k0","`","is","the","function","represented","by","`","base_kernel","`","-","`","k","`","is","an","the","function","represented","by","this","class","``","`","none","kxy","=","k0","(","x",",","y",")","kxz","=","k0","(","x",",","z",")","kzy","=","k0","(","z",",","y",")","kzz","=","k0","(","z",",","z",")","k","(","x",",","y",")","=","(","kxy","-","kxz","@","inv","(","kzz",")","@","kzy","+","kxz","@","inv","(","kzz",")","@","var_scale","@","var_scale^T","@","inv","(","kzz",")","@","kzy",")","``","`"]
code: def _compute_kernel(
      self,
      k12,
      k1z,
      k2z,
      chol_kzz,
      inducing_index_points,
      is_apply=True,
  ):
      variational_scale = tf.convert_to_tensor(self.variational_scale)
      kzzchol_linop = tf.linalg.LinearOperatorLowerTriangular(chol_kzz)
  
      if self.use_whitening_transform:
          kzz_chol_inv_kz2 = kzzchol_linop.solve(k2z, adjoint_arg=True)
          kzz_chol_inv_kz1 = kzzchol_linop.solve(k1z, adjoint_arg=True)
  
          var = -tf.linalg.matmul(
              variational_scale, variational_scale, adjoint_b=True
          )
          result = tf.linalg.set_diag(
              var, 1.0 + tf.linalg.diag_part(var)
          )
          if is_apply:
              result = tf.linalg.einsum(
                  "...ji,...jk,...ki->...i",
                  kzz_chol_inv_kz1,
                  result,
                  kzz_chol_inv_kz2,
              )
          else:
              result = tf.linalg.matmul(
                  tf.linalg.matmul(
                      kzz_chol_inv_kz1, result, adjoint_a=True
                  ),
                  kzz_chol_inv_kz2,
              )
          return k12 - result
  
      # Write out both solves explicitly. This is so that in the case x1 == x2,
      # CSE can ensure that only one solve / kernel computation is done.
      kzz_inv_kz2 = kzzchol_linop.solve(
          kzzchol_linop.solve(k2z, adjoint_arg=True), adjoint=True
      )
      kzz_inv_kz1 = kzzchol_linop.solve(
          kzzchol_linop.solve(k1z, adjoint_arg=True), adjoint=True
      )
  
      kzz = self.base_kernel.matrix(
          inducing_index_points, inducing_index_points
      )
      result = kzz - tf.linalg.matmul(
          variational_scale, variational_scale, adjoint_b=True
      )
      if is_apply:
          result = tf.linalg.einsum(
              "...ji,...jk,...ki->...i",
              kzz_inv_kz1,
              result,
              kzz_inv_kz2,
          )
      else:
          result = tf.linalg.matmul(
              tf.linalg.matmul(kzz_inv_kz1, result, adjoint_a=True),
              kzz_inv_kz2,
          )
      return k12 - result
  
imports: import numpy
  import tensorflow.compat.v2
  from tensorflow_probability.python import util
  from tensorflow_probability.python.bijectors import fill_scale_tril
  from tensorflow_probability.python.bijectors import softplus
  from tensorflow_probability.python.distributions import cholesky_util
  from tensorflow_probability.python.distributions import distribution
  from tensorflow_probability.python.distributions import gaussian_process
  from tensorflow_probability.python.distributions import independent
  from tensorflow_probability.python.distributions import kullback_leibler
  from tensorflow_probability.python.distributions import mvn_linear_operator
  from tensorflow_probability.python.distributions import normal
  from tensorflow_probability.python.distributions.internal import stochastic_process_util
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import parameter_properties
  from tensorflow_probability.python.internal import tensor_util
  from tensorflow_probability.python.internal import tensorshape_util
  from tensorflow_probability.python.math import linalg
  from tensorflow_probability.python.math.psd_kernels import positive_semidefinite_kernel
  from tensorflow_probability.python.math.psd_kernels.internal import util
label_desc: Use image node_id 8 for calling the _VariationalKernel obj's underlying member method code with example usage: obj._compute_kernel(k12, k1z, k2z, chol_kzz, inducing_index_points, is_apply) and returns: unknown, unknown