code: def _quadrature_expectation_gaussian(
      p: Union[Gaussian, DiagonalGaussian],
      obj1: ExpectationObject,
      inducing_variable1: Optional[InducingVariables],
      obj2: ExpectationObject,
      inducing_variable2: Optional[InducingVariables],
      nghp: Optional[int] = None,
  ) -> tf.Tensor:
      """
      General handling of quadrature expectations for Gaussians and DiagonalGaussians
      Fallback method for missing analytic expectations
      """
      nghp = 100 if nghp is None else nghp
  
      # logger.warning(
      #     "Quadrature is used to calculate the expectation. This means that "
      #     "an analytical implementations is not available for the given combination."
      # )
  
      if obj1 is None:
          raise NotImplementedError("First object cannot be None.")
  
      if not isinstance(p, DiagonalGaussian):
          cov = p.cov
      else:
          if (
              isinstance(obj1, kernels.Kernel)
              and isinstance(obj2, kernels.Kernel)
              and obj1.on_separate_dims(obj2)
          ):  # no joint expectations required
              eKxz1 = quadrature_expectation(
                  p,
                  cast(
                      PackedExpectationObject,
                      (obj1, inducing_variable1),
                  ),
                  nghp=nghp,
              )
              eKxz2 = quadrature_expectation(
                  p,
                  cast(
                      PackedExpectationObject,
                      (obj2, inducing_variable2),
                  ),
                  nghp=nghp,
              )
              return eKxz1[:, :, None] * eKxz2[:, None, :]
          cov = tf.linalg.diag(p.cov)
  
      if obj2 is None:
  
          def eval_func(x: TensorType) -> tf.Tensor:
              fn = get_eval_func(obj1, inducing_variable1)
              return fn(x)
  
      else:
  
          def eval_func(x: TensorType) -> tf.Tensor:
              fn1 = get_eval_func(
                  obj1, inducing_variable1, np.s_[:, :, None]
              )
              fn2 = get_eval_func(
                  obj2, inducing_variable2, np.s_[:, None, :]
              )
              return fn1(x) * fn2(x)
  
      return mvnquad(eval_func, p.mu, cov, nghp)
  
file_path: GPflow/gpflow/expectations/quadratures.py
imports: from typing import Any, Callable, Optional, Type, Union, cast
  import numpy
  import tensorflow
  from check_shapes import check_shapes
  from ..None import kernels
  from ..None import mean_functions
  from ..base import TensorType
  from ..covariances import Kuf
  from ..inducing_variables import InducingVariables
  from ..probability_distributions import DiagonalGaussian, Gaussian, MarkovGaussian
  from ..quadrature import mvnquad
  from .None import dispatch
  from .expectations import ExpectationObject, PackedExpectationObject, quadrature_expectation
label_desc: Use image node_id 2 for calling a global function with example usage: _quadrature_expectation_gaussian(p, obj1, inducing_variable1, obj2, inducing_variable2, nghp) and returns: mvnquad, unknown, fn, unknown