class_docstr: Conjugate Gradient Lower Bound.
  
  The key reference is :cite:t:`pmlr-v139-artemev21a`.
  
  :param cg_tolerance: Determines accuracy to which conjugate
      gradient is run when evaluating the elbo. Running more
      iterations of CG would increase the ELBO by at most
      `cg_tolerance`.
  
  :param max_cg_iters: Maximum number of iterations of CG to run
      per evaluation of the ELBO (or mean prediction).
  
  :param restart_cg_iters: How frequently to restart the CG iteration.
      Can be useful to avoid build up of numerical errors when
      many steps of CG are run.
  
  :param v_grad_optimization: If False, in every evaluation of the
      ELBO, CG is run to select a new auxilary vector `v`. If
      False, no CG is run when evaluating the ELBO but
      gradients with respect to `v` are tracked so that it can
      be optimized jointly with other parameters.
class_docstr_tok: ["Conjugate","Gradient","Lower","Bound",".","The","key","reference","is",":","cite",":","t",":","`","pmlr-v139-artemev21a","`",".",":","param","cg_tolerance",":","Determines","accuracy","to","which","conjugate","gradient","is","run","when","evaluating","the","elbo",".","Running","more","iterations","of","CG","would","increase","the","ELBO","by","at","most","`","cg_tolerance","`",".",":","param","max_cg_iters",":","Maximum","number","of","iterations","of","CG","to","run","per","evaluation","of","the","ELBO","(","or","mean","prediction",")",".",":","param","restart_cg_iters",":","How","frequently","to","restart","the","CG","iteration",".","Can","be","useful","to","avoid","build","up","of","numerical","errors","when","many","steps","of","CG","are","run",".",":","param","v_grad_optimization",":","If","False",",","in","every","evaluation","of","the","ELBO",",","CG","is","run","to","select","a","new","auxilary","vector","`","v","`",".","If","False",",","no","CG","is","run","when","evaluating","the","ELBO","but","gradients","with","respect","to","`","v","`","are","tracked","so","that","it","can","be","optimized","jointly","with","other","parameters","."]
docstr: Computes a lower bound on the quadratic term in the log
  marginal likelihood of conjugate GPR. The bound is based on
  an auxiliary vector, v. For :math:`Q ≺ K` and :math:`r=y - Kv`
  
  .. math::
      -0.5 * (rᵀQ⁻¹r + 2yᵀv - vᵀ K v ) <= -0.5 * yᵀK⁻¹y <= -0.5 * (2yᵀv - vᵀKv).
  
  Equality holds if :math:`r=0`, i.e. :math:`v = K⁻¹y`.
  
  If `self.aux_vec` is trainable, gradients are computed with
  respect to :math:`v` as well and :math:`v` can be optimized
  using gradient based methods.
  
  Otherwise, :math:`v` is updated with the method of conjugate
  gradients (CG). CG is run until :math:`0.5 * rᵀQ⁻¹r <= ϵ`,
  which ensures that the maximum bias due to this term is not
  more than :math:`ϵ`. The :math:`ϵ` is the CG tolerance.
docstr_tok: ["Computes","a","lower","bound","on","the","quadratic","term","in","the","log","marginal","likelihood","of","conjugate","GPR",".","The","bound","is","based","on","an","auxiliary","vector",",","v.","For",":","math",":","`","Q","\u227a","K","`","and",":","math",":","`","r=y","-","Kv","`","..","math",":",":","-0.5","*","(","r\u1d40Q\u207b\u00b9r","+","2y\u1d40v","-","v\u1d40","K","v",")","<","=","-0.5","*","y\u1d40K\u207b\u00b9y","<","=","-0.5","*","(","2y\u1d40v","-","v\u1d40Kv",")",".","Equality","holds","if",":","math",":","`","r=0","`",",","i.e",".",":","math",":","`","v","=","K\u207b\u00b9y","`",".","If","`","self.aux_vec","`","is","trainable",",","gradients","are","computed","with","respect","to",":","math",":","`","v","`","as","well","and",":","math",":","`","v","`","can","be","optimized","using","gradient","based","methods",".","Otherwise",",",":","math",":","`","v","`","is","updated","with","the","method","of","conjugate","gradients","(","CG",")",".","CG","is","run","until",":","math",":","`","0.5","*","r\u1d40Q\u207b\u00b9r","<","=","\u03f5","`",",","which","ensures","that","the","maximum","bias","due","to","this","term","is","not","more","than",":","math",":","`","\u03f5","`",".","The",":","math",":","`","\u03f5","`","is","the","CG","tolerance","."]
code: def quad_term(self, common: SGPR.CommonTensors) -> tf.Tensor:
      """
      Computes a lower bound on the quadratic term in the log
      marginal likelihood of conjugate GPR. The bound is based on
      an auxiliary vector, v. For :math:`Q ≺ K` and :math:`r=y - Kv`
  
      .. math::
          -0.5 * (rᵀQ⁻¹r + 2yᵀv - vᵀ K v ) <= -0.5 * yᵀK⁻¹y <= -0.5 * (2yᵀv - vᵀKv).
  
      Equality holds if :math:`r=0`, i.e. :math:`v = K⁻¹y`.
  
      If `self.aux_vec` is trainable, gradients are computed with
      respect to :math:`v` as well and :math:`v` can be optimized
      using gradient based methods.
  
      Otherwise, :math:`v` is updated with the method of conjugate
      gradients (CG). CG is run until :math:`0.5 * rᵀQ⁻¹r <= ϵ`,
      which ensures that the maximum bias due to this term is not
      more than :math:`ϵ`. The :math:`ϵ` is the CG tolerance.
      """
      x, y = self.data
      err = y - self.mean_function(x)
      sigma_sq = self.likelihood.variance
      K = add_noise_cov(self.kernel.K(x), sigma_sq)
  
      A = common.A
      LB = common.LB
      preconditioner = NystromPreconditioner(A, LB, sigma_sq)
      err_t = tf.transpose(err)
  
      v_init = self.aux_vec
      if not v_init.trainable:
          v = cglb_conjugate_gradient(
              K,
              err_t,
              v_init,
              preconditioner,
              self._cg_tolerance,
              self._max_cg_iters,
              self._restart_cg_iters,
          )
      else:
          v = v_init
  
      Kv = v @ K
      r = err_t - Kv
      _, error_bound = preconditioner(r)
      lb = tf.reduce_sum(v * (r + 0.5 * Kv))
      ub = lb + 0.5 * error_bound
  
      if not v_init.trainable:
          v_init.assign(v)
  
      return -ub
  
imports: from typing import Any, List, NamedTuple, Optional, Tuple
  import tensorflow
  from check_shapes import check_shapes, inherit_check_shapes
  from ..base import InputData, MeanAndVariance, Parameter, RegressionData, TensorType
  from ..config import default_float, default_int
  from ..covariances import Kuf
  from ..utilities import add_noise_cov, assert_params_false, to_default_float
  from .sgpr import SGPR
label_desc: Use image node_id 4 for calling the CGLB obj's underlying member method code with example usage: obj.quad_term(common) and returns: unknown